目录

1 前提准备

1.1 载入包

library(nycflights13)
程辑包‘nycflights13’是用R版本3.3.2 来建造的
library(tidyverse)
程辑包‘tidyverse’是用R版本3.3.2 来建造的Loading tidyverse: ggplot2
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
Loading tidyverse: dplyr
程辑包‘ggplot2’是用R版本3.3.2 来建造的程辑包‘tidyr’是用R版本3.3.2 来建造的程辑包‘readr’是用R版本3.3.2 来建造的程辑包‘purrr’是用R版本3.3.2 来建造的程辑包‘dplyr’是用R版本3.3.2 来建造的Conflicts with tidy packages -------------------------------------------------------------------------------------
filter(): dplyr, stats
lag():    dplyr, stats

1.2 flights 数据集

  • flights 数据集以 tibble 形式存储
flights
#> # A tibble: 336,776 × 19
#>    year month   day dep_time sched_dep_time dep_delay arr_time
#>   <int> <int> <int>    <int>          <int>     <dbl>    <int>
#> 1  2013     1     1      517            515         2      830
#> 2  2013     1     1      533            529         4      850
#> 3  2013     1     1      542            540         2      923
#> 4  2013     1     1      544            545        -1     1004
#> 5  2013     1     1      554            600        -6      812
#> 6  2013     1     1      554            558        -4      740
#> # ... with 3.368e+05 more rows, and 12 more variables:
#> #   sched_arr_time <int>, arr_delay <dbl>, carrier <chr>, flight <int>,
#> #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
#> #   distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
  • 使用 View 可以观察完整的 flights 数据集

    View(flights)

1.3 数据类型介绍

  • int stands for integers.

  • dbl stands for doubles, or real numbers.

  • chr stands for character vectors, or strings.

  • dttm stands for date-times (a date + a time).

  • lgl stands for logical, vectors that contain only TRUE or FALSE.

  • fctr stands for factors, which R uses to represent categorical variables with fixed possible values.

  • date stands for dates.

1.4 dplyr 基础

接下来,将会接触到5种核心的 dplyr 函数

  • Pick observations by their values filter().

  • Reorder the rows arrange().

  • Pick variables by their names select().

  • Create new variables with functions of existing variables mutate().

  • Collapse many values down to a single summary summarise().

2 用 filter() 筛选行

2.1 按给定的逻辑判断筛选出符合要求的子数据集, 类似于 base::subset() 函数

filter(flights, month == 1, day == 1)
#> # A tibble: 842 × 19
#>    year month   day dep_time sched_dep_time dep_delay arr_time
#>   <int> <int> <int>    <int>          <int>     <dbl>    <int>
#> 1  2013     1     1      517            515         2      830
#> 2  2013     1     1      533            529         4      850
#> 3  2013     1     1      542            540         2      923
#> 4  2013     1     1      544            545        -1     1004
#> 5  2013     1     1      554            600        -6      812
#> 6  2013     1     1      554            558        -4      740
#> # ... with 836 more rows, and 12 more variables: sched_arr_time <int>,
#> #   arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>,
#> #   origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
#> #   minute <dbl>, time_hour <dttm>
(dec25 <- filter(flights, month == 12, day == 25))
#> # A tibble: 719 × 19
#>    year month   day dep_time sched_dep_time dep_delay arr_time
#>   <int> <int> <int>    <int>          <int>     <dbl>    <int>
#> 1  2013    12    25      456            500        -4      649
#> 2  2013    12    25      524            515         9      805
#> 3  2013    12    25      542            540         2      832
#> 4  2013    12    25      546            550        -4     1022
#> 5  2013    12    25      556            600        -4      730
#> 6  2013    12    25      557            600        -3      743
#> # ... with 713 more rows, and 12 more variables: sched_arr_time <int>,
#> #   arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>,
#> #   origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
#> #   minute <dbl>, time_hour <dttm>

2.2 对某个变量选取两个或以上的值

filter(flights, month == 11 | month == 12)
filter(flights, month %in% c(11, 12))

2.3 缺失值

  • NA (“not availables”) 代表缺失值,在计算中有“传染性”:对 NA 进行任意操作,都会返回 NA
NA > 5
[1] NA
10 == NA
[1] NA
NA + 10
[1] NA
NA / 2
[1] NA
NA == NA
[1] NA
x <- NA
y <- NA
x == y
[1] NA
  • is.na() 判断是否为缺失值
is.na(x)
[1] TRUE
df <- tibble(x = c(1, NA, 3))
filter(df, x > 1)
#> # A tibble: 1 × 1
#>       x
#>   <dbl>
#> 1     3
  • filter() 会排除 FalseNA 的行,仅仅返回结果为 True 的行。如果想要保留缺失值,需要进行显式声明
filter(df, is.na(x) | x > 1)
#> # A tibble: 2 × 1
#>       x
#>   <dbl>
#> 1    NA
#> 2     3

2.4 between()

df <- tibble(x = c(1, 2, 2, 3, 4))
filter(df, between(x, 1, 3))
#> # A tibble: 4 × 1
#>       x
#>   <dbl>
#> 1     1
#> 2     2
#> 3     2
#> 4     3

3 用 arrange() 排列行

arrange(flights, year, month, day)
#> # A tibble: 336,776 × 19
#>    year month   day dep_time sched_dep_time dep_delay arr_time
#>   <int> <int> <int>    <int>          <int>     <dbl>    <int>
#> 1  2013     1     1      517            515         2      830
#> 2  2013     1     1      533            529         4      850
#> 3  2013     1     1      542            540         2      923
#> 4  2013     1     1      544            545        -1     1004
#> 5  2013     1     1      554            600        -6      812
#> 6  2013     1     1      554            558        -4      740
#> # ... with 3.368e+05 more rows, and 12 more variables:
#> #   sched_arr_time <int>, arr_delay <dbl>, carrier <chr>, flight <int>,
#> #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
#> #   distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
arrange(flights, desc(arr_delay))
#> # A tibble: 336,776 × 19
#>    year month   day dep_time sched_dep_time dep_delay arr_time
#>   <int> <int> <int>    <int>          <int>     <dbl>    <int>
#> 1  2013     1     9      641            900      1301     1242
#> 2  2013     6    15     1432           1935      1137     1607
#> 3  2013     1    10     1121           1635      1126     1239
#> 4  2013     9    20     1139           1845      1014     1457
#> 5  2013     7    22      845           1600      1005     1044
#> 6  2013     4    10     1100           1900       960     1342
#> # ... with 3.368e+05 more rows, and 12 more variables:
#> #   sched_arr_time <int>, arr_delay <dbl>, carrier <chr>, flight <int>,
#> #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
#> #   distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
df <- tibble(x = c(5, 2, NA))
arrange(df, x)
#> # A tibble: 3 × 1
#>       x
#>   <dbl>
#> 1     2
#> 2     5
#> 3    NA
arrange(df, desc(x))
#> # A tibble: 3 × 1
#>       x
#>   <dbl>
#> 1     5
#> 2     2
#> 3    NA

4 用 select() 筛选列

4.1 基本用法

  • 选择year、month、day列
select(flights, year, month, day)
#> # A tibble: 336,776 × 3
#>    year month   day
#>   <int> <int> <int>
#> 1  2013     1     1
#> 2  2013     1     1
#> 3  2013     1     1
#> 4  2013     1     1
#> 5  2013     1     1
#> 6  2013     1     1
#> # ... with 3.368e+05 more rows
  • 选择year和day之间的列(包括)
select(flights, year:day)
#> # A tibble: 336,776 × 3
#>    year month   day
#>   <int> <int> <int>
#> 1  2013     1     1
#> 2  2013     1     1
#> 3  2013     1     1
#> 4  2013     1     1
#> 5  2013     1     1
#> 6  2013     1     1
#> # ... with 3.368e+05 more rows
  • 选择除year和day之间的列以外的所有列(包括)
select(flights, -(year:day))
#> # A tibble: 336,776 × 16
#>   dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay
#>      <int>          <int>     <dbl>    <int>          <int>     <dbl>
#> 1      517            515         2      830            819        11
#> 2      533            529         4      850            830        20
#> 3      542            540         2      923            850        33
#> 4      544            545        -1     1004           1022       -18
#> 5      554            600        -6      812            837       -25
#> 6      554            558        -4      740            728        12
#> # ... with 3.368e+05 more rows, and 10 more variables: carrier <chr>,
#> #   flight <int>, tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
#> #   distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

4.2 Helper Functions

  • starts_with(x, ignore.case = TRUE): names starts with x.

  • ends_with(x, ignore.case = TRUE): names ends in x.

  • contains(x, ignore.case = TRUE): selects all variables whose name contains x.

  • matches(x, ignore.case = TRUE): selects all variables whose name matches the regular expression x.

  • num_range("x", 1:5, width = 2): selects all variables (numerically) from x01 to x05.

  • one_of("x", "y", "z"): selects variables provided in a character vector.

  • everything(): selects all variables.

4.3 利用 everything() 将列移到最前面

select(flights, time_hour, air_time, everything())
#> # A tibble: 336,776 × 19
#>             time_hour air_time  year month   day dep_time sched_dep_time
#>                <dttm>    <dbl> <int> <int> <int>    <int>          <int>
#> 1 2013-01-01 05:00:00      227  2013     1     1      517            515
#> 2 2013-01-01 05:00:00      227  2013     1     1      533            529
#> 3 2013-01-01 05:00:00      160  2013     1     1      542            540
#> 4 2013-01-01 05:00:00      183  2013     1     1      544            545
#> 5 2013-01-01 06:00:00      116  2013     1     1      554            600
#> 6 2013-01-01 05:00:00      150  2013     1     1      554            558
#> # ... with 3.368e+05 more rows, and 12 more variables: dep_delay <dbl>,
#> #   arr_time <int>, sched_arr_time <int>, arr_delay <dbl>, carrier <chr>,
#> #   flight <int>, tailnum <chr>, origin <chr>, dest <chr>, distance <dbl>,
#> #   hour <dbl>, minute <dbl>

4.4 rename() 函数

rename(flights, tail_num = tailnum)
#> # A tibble: 336,776 × 19
#>    year month   day dep_time sched_dep_time dep_delay arr_time
#>   <int> <int> <int>    <int>          <int>     <dbl>    <int>
#> 1  2013     1     1      517            515         2      830
#> 2  2013     1     1      533            529         4      850
#> 3  2013     1     1      542            540         2      923
#> 4  2013     1     1      544            545        -1     1004
#> 5  2013     1     1      554            600        -6      812
#> 6  2013     1     1      554            558        -4      740
#> # ... with 3.368e+05 more rows, and 12 more variables:
#> #   sched_arr_time <int>, arr_delay <dbl>, carrier <chr>, flight <int>,
#> #   tail_num <chr>, origin <chr>, dest <chr>, air_time <dbl>,
#> #   distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

5 用 mutate() 添加列

5.1 基本用法

  • 对已有列进行数据运算并添加为新列
flights_sml <- select(flights, 
  year:day, 
  ends_with("delay"), 
  distance, 
  air_time
)
mutate(flights_sml,
  gain = arr_delay - dep_delay,
  speed = distance / air_time * 60
)
#> # A tibble: 336,776 × 9
#>    year month   day dep_delay arr_delay distance air_time  gain speed
#>   <int> <int> <int>     <dbl>     <dbl>    <dbl>    <dbl> <dbl> <dbl>
#> 1  2013     1     1         2        11     1400      227     9   370
#> 2  2013     1     1         4        20     1416      227    16   374
#> 3  2013     1     1         2        33     1089      160    31   408
#> 4  2013     1     1        -1       -18     1576      183   -17   517
#> 5  2013     1     1        -6       -25      762      116   -19   394
#> 6  2013     1     1        -4        12      719      150    16   288
#> # ... with 3.368e+05 more rows
  • 可以在同一语句中对刚增加的列进行操作
mutate(flights_sml,
  gain = arr_delay - dep_delay,
  hours = air_time / 60,
  gain_per_hour = gain / hours
)
#> # A tibble: 336,776 × 10
#>    year month   day dep_delay arr_delay distance air_time  gain hours
#>   <int> <int> <int>     <dbl>     <dbl>    <dbl>    <dbl> <dbl> <dbl>
#> 1  2013     1     1         2        11     1400      227     9  3.78
#> 2  2013     1     1         4        20     1416      227    16  3.78
#> 3  2013     1     1         2        33     1089      160    31  2.67
#> 4  2013     1     1        -1       -18     1576      183   -17  3.05
#> 5  2013     1     1        -6       -25      762      116   -19  1.93
#> 6  2013     1     1        -4        12      719      150    16  2.50
#> # ... with 3.368e+05 more rows, and 1 more variables: gain_per_hour <dbl>
  • transmute() 仅仅保留新增的列
transmute(flights,
  gain = arr_delay - dep_delay,
  hours = air_time / 60,
  gain_per_hour = gain / hours
)
#> # A tibble: 336,776 × 3
#>    gain hours gain_per_hour
#>   <dbl> <dbl>         <dbl>
#> 1     9  3.78          2.38
#> 2    16  3.78          4.23
#> 3    31  2.67         11.62
#> 4   -17  3.05         -5.57
#> 5   -19  1.93         -9.83
#> 6    16  2.50          6.40
#> # ... with 3.368e+05 more rows

5.2 可以用于计算新变量的向量化运算符

  • Arithmetic operators: +, -, *, /, ^.

  • Modular arithmetic: %/% (integer division) and %% (remainder).

transmute(flights,
  dep_time,
  hour = dep_time %/% 100,
  minute = dep_time %% 100
)
#> # A tibble: 336,776 × 3
#>   dep_time  hour minute
#>      <int> <dbl>  <dbl>
#> 1      517     5     17
#> 2      533     5     33
#> 3      542     5     42
#> 4      544     5     44
#> 5      554     5     54
#> 6      554     5     54
#> # ... with 3.368e+05 more rows
  • Logs: log(), log2(), log10().

  • Offsets: lead() and lag() allow you to refer to leading or lagging values.

(x <- 1:10)
 [1]  1  2  3  4  5  6  7  8  9 10
lag(x)
 [1] NA  1  2  3  4  5  6  7  8  9
lead(x)
 [1]  2  3  4  5  6  7  8  9 10 NA
# compute running differences
x - lag(x)
 [1] NA  1  1  1  1  1  1  1  1  1
# find when values change
x != lag(x)
 [1]   NA TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
  • Cumulative and rolling aggregates: cumsum(), cumprod(), cummin(), cummax(), cummean().
    If you need rolling aggregates (i.e. a sum computed over a rolling window), try the RcppRoll package.
x
 [1]  1  2  3  4  5  6  7  8  9 10
cumsum(x)
 [1]  1  3  6 10 15 21 28 36 45 55
cummean(x)
 [1] 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5
  • Logical comparisons, <, <=, >, >=, !=.

  • Ranking: min_rank(), row_number(), dense_rank(), percent_rank(), cume_dist(), ntile().

(y <- c(1, 2, 2, NA, 3, 4))
[1]  1  2  2 NA  3  4
min_rank(y)
[1]  1  2  2 NA  4  5
min_rank(desc(y))
[1]  5  3  3 NA  2  1
row_number(y)
[1]  1  2  3 NA  4  5
dense_rank(y)
[1]  1  2  2 NA  3  4
percent_rank(y)
[1] 0.00 0.25 0.25   NA 0.75 1.00
cume_dist(y)
[1] 0.2 0.6 0.6  NA 0.8 1.0

6 用 summarise() 计算分组统计量

6.1 group_by()summarise() 联合使用,计算分组统计量

summarise(flights, delay = mean(dep_delay, na.rm = TRUE))
#> # A tibble: 1 × 1
#>   delay
#>   <dbl>
#> 1  12.6
by_day <- group_by(flights, year, month, day)
summarise(by_day, delay = mean(dep_delay, na.rm = TRUE))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#> 
#>    year month   day delay
#>   <int> <int> <int> <dbl>
#> 1  2013     1     1 11.55
#> 2  2013     1     2 13.86
#> 3  2013     1     3 10.99
#> 4  2013     1     4  8.95
#> 5  2013     1     5  5.73
#> 6  2013     1     6  7.15
#> # ... with 359 more rows

6.2 管道操作符 %>%

  • 探索对于不同地点,平均飞行距离与平均延误时间之间的关系。可以发现,平均飞行距离为750英里时,平均延误时间达到峰值,可能是由于更长的飞行距离,为弥补延误提供了可能。
by_dest <- group_by(flights, dest)
delay <- summarise(by_dest,
  count = n(),
  dist = mean(distance, na.rm = TRUE),
  delay = mean(arr_delay, na.rm = TRUE)
)
(delay <- filter(delay, count > 20, dest != "HNL"))
#> # A tibble: 96 × 4
#>     dest count      dist     delay
#>    <chr> <int>     <dbl>     <dbl>
#> 1    ABQ   254 1826.0000  4.381890
#> 2    ACK   265  199.0000  4.852273
#> 3    ALB   439  143.0000 14.397129
#> 4    ATL 17215  757.1082 11.300113
#> 5    AUS  2439 1514.2530  6.019909
#> 6    AVL   275  583.5818  8.003831
#> 7    BDL   443  116.0000  7.048544
#> 8    BGR   375  378.0000  8.027933
#> 9    BHM   297  865.9966 16.877323
#> 10   BNA  6333  758.2135 11.812459
#> # ... with 86 more rows
ggplot(data = delay, mapping = aes(x = dist, y = delay)) +
  geom_point(aes(size = count), alpha = 1/3) +
  geom_smooth(se = FALSE)

  • 数据预处理涉及3个步骤:
    • 依据目的地分组
    • 计算分组后的平均飞行距离、平均延误时间和航班数
    • 过滤掉夏威夷机场(平均飞行距离是其他机场的2倍以上)和航班数过少的目的地
  • 使用管道操作符 %>% 完成以上3个步骤
delays <- flights %>% 
  group_by(dest) %>% 
  summarise(
    count = n(),
    dist = mean(distance, na.rm = TRUE),
    delay = mean(arr_delay, na.rm = TRUE)
  ) %>% 
  filter(count > 20, dest != "HNL")

6.3 缺失值

  • 缺失值传入聚合函数,也会返回缺失值
flights %>% 
  group_by(year, month, day) %>% 
  summarise(mean = mean(dep_delay))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#> 
#>    year month   day  mean
#>   <int> <int> <int> <dbl>
#> 1  2013     1     1    NA
#> 2  2013     1     2    NA
#> 3  2013     1     3    NA
#> 4  2013     1     4    NA
#> 5  2013     1     5    NA
#> 6  2013     1     6    NA
#> # ... with 359 more rows
  • 使用 na.rm 参数
flights %>% 
  group_by(year, month, day) %>% 
  summarise(mean = mean(dep_delay, na.rm = TRUE))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#> 
#>    year month   day  mean
#>   <int> <int> <int> <dbl>
#> 1  2013     1     1 11.55
#> 2  2013     1     2 13.86
#> 3  2013     1     3 10.99
#> 4  2013     1     4  8.95
#> 5  2013     1     5  5.73
#> 6  2013     1     6  7.15
#> # ... with 359 more rows
  • 先行剔除 NA
not_cancelled <- flights %>% 
  filter(!is.na(dep_delay), !is.na(arr_delay))
not_cancelled %>% 
  group_by(year, month, day) %>% 
  summarise(mean = mean(dep_delay))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#> 
#>    year month   day  mean
#>   <int> <int> <int> <dbl>
#> 1  2013     1     1 11.44
#> 2  2013     1     2 13.68
#> 3  2013     1     3 10.91
#> 4  2013     1     4  8.97
#> 5  2013     1     5  5.73
#> 6  2013     1     6  7.15
#> # ... with 359 more rows

6.4 计数(count

在计算分组统计量的时候,需要考虑组内样本的个数(n())、非缺失值的个数(sum(!is.na(x)))以及分组的个数

  • tailnum 区分飞机,用核密度图分析飞机的平均延误时间分布情况
delays <- not_cancelled %>% 
  group_by(tailnum) %>% 
  summarise(
    delay = mean(arr_delay)
  )
delays
#> # A tibble: 4,037 × 2
#>    tailnum      delay
#>      <chr>      <dbl>
#> 1   D942DN 31.5000000
#> 2   N0EGMQ  9.9829545
#> 3   N10156 12.7172414
#> 4   N102UW  2.9375000
#> 5   N103US -6.9347826
#> 6   N104UW  1.8043478
#> 7   N10575 20.6914498
#> 8   N105UW -0.2666667
#> 9   N107US -5.7317073
#> 10  N108UW -1.2500000
#> # ... with 4,027 more rows
ggplot(data = delays, mapping = aes(x = delay)) + 
  geom_freqpoly(binwidth = 10)

  • n() 计算组内样本个数,从散点图可以看出,飞行次数少的飞机,平均延误时间的变异程度更大
delays <- not_cancelled %>% 
  group_by(tailnum) %>% 
  summarise(
    delay = mean(arr_delay, na.rm = TRUE),
    n = n()
  )
delays
#> # A tibble: 4,037 × 3
#>    tailnum      delay     n
#>      <chr>      <dbl> <int>
#> 1   D942DN 31.5000000     4
#> 2   N0EGMQ  9.9829545   352
#> 3   N10156 12.7172414   145
#> 4   N102UW  2.9375000    48
#> 5   N103US -6.9347826    46
#> 6   N104UW  1.8043478    46
#> 7   N10575 20.6914498   269
#> 8   N105UW -0.2666667    45
#> 9   N107US -5.7317073    41
#> 10  N108UW -1.2500000    60
#> # ... with 4,027 more rows
ggplot(data = delays, mapping = aes(x = n, y = delay)) + 
  geom_point(alpha = 1/10)

  • 利用 filter() 筛选出飞行次数大于25的飞机,分析它们的延误情况

  • ba 代表击打成功率, ab 代表击打次数,击打成功率与击打数正相关,可能是因为球队倾向于让成功率高的球员拥有更多出场机会
# Convert to a tibble so it prints nicely
batting <- as_tibble(Lahman::Batting)
batters <- batting %>% 
  group_by(playerID) %>% 
  summarise(
    ba = sum(H, na.rm = TRUE) / sum(AB, na.rm = TRUE),
    ab = sum(AB, na.rm = TRUE)
  )
batters %>% 
  filter(ab > 100) %>% 
  ggplot(mapping = aes(x = ab, y = ba)) +
    geom_point() + 
    geom_smooth(se = FALSE)

  • 依据 ba 进行降序排列,可以看出,击打成功率最高的球员,击打次数只有一次,纯粹是由于运气而非技术
batters %>% 
  arrange(desc(ba))
#> # A tibble: 18,659 × 3
#>    playerID    ba    ab
#>       <chr> <dbl> <int>
#> 1 abramge01     1     1
#> 2 banisje01     1     1
#> 3 bartocl01     1     1
#> 4  bassdo01     1     1
#> 5 birasst01     1     2
#> 6 bruneju01     1     1
#> # ... with 1.865e+04 more rows

6.5 聚合统计函数

  • Measures of location: mean(x), median(x).
not_cancelled %>% 
  group_by(year, month, day) %>% 
  summarise(
    avg_delay1 = mean(arr_delay),
    avg_delay2 = mean(arr_delay[arr_delay > 0]) # the average positive delay
  )
#> Source: local data frame [365 x 5]
#> Groups: year, month [?]
#> 
#>    year month   day avg_delay1 avg_delay2
#>   <int> <int> <int>      <dbl>      <dbl>
#> 1  2013     1     1      12.65       32.5
#> 2  2013     1     2      12.69       32.0
#> 3  2013     1     3       5.73       27.7
#> 4  2013     1     4      -1.93       28.3
#> 5  2013     1     5      -1.53       22.6
#> 6  2013     1     6       4.24       24.4
#> # ... with 359 more rows
  • Measures of spread: sd(x), IQR(x), mad(x).
# Why is distance to some destinations more variable than to others?
not_cancelled %>% 
  group_by(dest) %>% 
  summarise(distance_sd = sd(distance)) %>% 
  arrange(desc(distance_sd))
#> # A tibble: 104 × 2
#>    dest distance_sd
#>   <chr>       <dbl>
#> 1   EGE       10.54
#> 2   SAN       10.35
#> 3   SFO       10.22
#> 4   HNL       10.00
#> 5   SEA        9.98
#> 6   LAS        9.91
#> # ... with 98 more rows
  • Measures of rank: min(x), quantile(x, 0.25), max(x).
# When do the first and last flights leave each day?
not_cancelled %>% 
  group_by(year, month, day) %>% 
  summarise(
    first = min(dep_time),
    last = max(dep_time)
  )
#> Source: local data frame [365 x 5]
#> Groups: year, month [?]
#> 
#>    year month   day first  last
#>   <int> <int> <int> <int> <int>
#> 1  2013     1     1   517  2356
#> 2  2013     1     2    42  2354
#> 3  2013     1     3    32  2349
#> 4  2013     1     4    25  2358
#> 5  2013     1     5    14  2357
#> 6  2013     1     6    16  2355
#> # ... with 359 more rows
  • Measures of position: first(x), nth(x, 2), last(x).
not_cancelled %>% 
  group_by(year, month, day) %>% 
  summarise(
    first_dep = first(dep_time), 
    last_dep = last(dep_time)
  )
#> Source: local data frame [365 x 5]
#> Groups: year, month [?]
#> 
#>    year month   day first_dep last_dep
#>   <int> <int> <int>     <int>    <int>
#> 1  2013     1     1       517     2356
#> 2  2013     1     2        42     2354
#> 3  2013     1     3        32     2349
#> 4  2013     1     4        25     2358
#> 5  2013     1     5        14     2357
#> 6  2013     1     6        16     2355
#> # ... with 359 more rows

同样的效果,可以通过以下方法实现,并且会保留所有的变量,注意 mutate(), min_rank, filter() 在这里的作用

not_cancelled %>% 
  group_by(year, month, day) %>% 
  mutate(r = min_rank(desc(dep_time))) %>% 
  filter(r %in% range(r))
#> Source: local data frame [770 x 20]
#> Groups: year, month, day [365]
#> 
#>    year month   day dep_time sched_dep_time dep_delay arr_time
#>   <int> <int> <int>    <int>          <int>     <dbl>    <int>
#> 1  2013     1     1      517            515         2      830
#> 2  2013     1     1     2356           2359        -3      425
#> 3  2013     1     2       42           2359        43      518
#> 4  2013     1     2     2354           2359        -5      413
#> 5  2013     1     3       32           2359        33      504
#> 6  2013     1     3     2349           2359       -10      434
#> # ... with 764 more rows, and 13 more variables: sched_arr_time <int>,
#> #   arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>,
#> #   origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
#> #   minute <dbl>, time_hour <dttm>, r <int>
  • Counts: count(), n(), sum(!is.na(x)), n_distinct(x).
# Which destinations have the most carriers?
not_cancelled %>% 
  group_by(dest) %>% 
  summarise(carriers = n_distinct(carrier)) %>% 
  arrange(desc(carriers))
#> # A tibble: 104 × 2
#>    dest carriers
#>   <chr>    <int>
#> 1   ATL        7
#> 2   BOS        7
#> 3   CLT        7
#> 4   ORD        7
#> 5   TPA        7
#> 6   AUS        6
#> # ... with 98 more rows

强大的 count() 函数,此处计算每个机场作为目的地的航班数

not_cancelled %>% 
  count(dest)
#> # A tibble: 104 × 2
#>    dest     n
#>   <chr> <int>
#> 1   ABQ   254
#> 2   ACK   264
#> 3   ALB   418
#> 4   ANC     8
#> 5   ATL 16837
#> 6   AUS  2411
#> # ... with 98 more rows

count() 可以用于加权计数,此处计算每架飞机的总飞行里程

not_cancelled %>% 
  count(tailnum, wt = distance)
#> # A tibble: 4,037 × 2
#>   tailnum      n
#>     <chr>  <dbl>
#> 1  D942DN   3418
#> 2  N0EGMQ 239143
#> 3  N10156 109664
#> 4  N102UW  25722
#> 5  N103US  24619
#> 6  N104UW  24616
#> # ... with 4,031 more rows
  • Counts and proportions of logical values: sum(x > 10), mean(y == 0). sum(x) gives the number of TRUEs in x, and mean(x) gives the proportion.
# How many flights left before 5am? (these usually indicate delayed
# flights from the previous day)
not_cancelled %>% 
  group_by(year, month, day) %>% 
  summarise(n_early = sum(dep_time < 500))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#> 
#>    year month   day n_early
#>   <int> <int> <int>   <int>
#> 1  2013     1     1       0
#> 2  2013     1     2       3
#> 3  2013     1     3       4
#> 4  2013     1     4       3
#> 5  2013     1     5       3
#> 6  2013     1     6       2
#> # ... with 359 more rows
# What proportion of flights are delayed by more than an hour?
not_cancelled %>% 
  group_by(year, month, day) %>% 
  summarise(hour_perc = mean(arr_delay > 60))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#> 
#>    year month   day hour_perc
#>   <int> <int> <int>     <dbl>
#> 1  2013     1     1    0.0722
#> 2  2013     1     2    0.0851
#> 3  2013     1     3    0.0567
#> 4  2013     1     4    0.0396
#> 5  2013     1     5    0.0349
#> 6  2013     1     6    0.0470
#> # ... with 359 more rows

6.6 依据多个变量进行分组

创建依据多个变量的分组后,每一次 summarise都会剥离一层分组变量

  • 依据year, month, day 三个变量分组
daily <- group_by(flights, year, month, day)
(per_day   <- summarise(daily, flights = n()))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#> 
#>    year month   day flights
#>   <int> <int> <int>   <int>
#> 1  2013     1     1     842
#> 2  2013     1     2     943
#> 3  2013     1     3     914
#> 4  2013     1     4     915
#> 5  2013     1     5     720
#> 6  2013     1     6     832
#> # ... with 359 more rows
  • summarise 后,剥离 day 变量
(per_month <- summarise(per_day, flights = sum(flights)))
#> Source: local data frame [12 x 3]
#> Groups: year [?]
#> 
#>    year month flights
#>   <int> <int>   <int>
#> 1  2013     1   27004
#> 2  2013     2   24951
#> 3  2013     3   28834
#> 4  2013     4   28330
#> 5  2013     5   28796
#> 6  2013     6   28243
#> # ... with 6 more rows
  • summarise 后,剥离 month 变量
(per_year  <- summarise(per_month, flights = sum(flights)))
#> # A tibble: 1 × 2
#>    year flights
#>   <int>   <int>
#> 1  2013  336776

6.7 取消分组

daily %>% 
  ungroup() %>%             # no longer grouped by date
  summarise(flights = n())  # all flights
#> # A tibble: 1 × 1
#>   flights
#>     <int>
#> 1  336776

7 分组变换(mutate(), filter()

flights_sml %>% 
  group_by(year, month, day) %>%
  filter(rank(desc(arr_delay)) < 10)
#> Source: local data frame [3,306 x 7]
#> Groups: year, month, day [365]
#> 
#>    year month   day dep_delay arr_delay distance air_time
#>   <int> <int> <int>     <dbl>     <dbl>    <dbl>    <dbl>
#> 1  2013     1     1       853       851      184       41
#> 2  2013     1     1       290       338     1134      213
#> 3  2013     1     1       260       263      266       46
#> 4  2013     1     1       157       174      213       60
#> 5  2013     1     1       216       222      708      121
#> 6  2013     1     1       255       250      589      115
#> # ... with 3,300 more rows
popular_dests <- flights %>% 
  group_by(dest) %>% 
  filter(n() > 365)
popular_dests
#> Source: local data frame [332,577 x 19]
#> Groups: dest [77]
#> 
#>    year month   day dep_time sched_dep_time dep_delay arr_time
#>   <int> <int> <int>    <int>          <int>     <dbl>    <int>
#> 1  2013     1     1      517            515         2      830
#> 2  2013     1     1      533            529         4      850
#> 3  2013     1     1      542            540         2      923
#> 4  2013     1     1      544            545        -1     1004
#> 5  2013     1     1      554            600        -6      812
#> 6  2013     1     1      554            558        -4      740
#> # ... with 3.326e+05 more rows, and 12 more variables:
#> #   sched_arr_time <int>, arr_delay <dbl>, carrier <chr>, flight <int>,
#> #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
#> #   distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
popular_dests %>% 
  filter(arr_delay > 0) %>% 
  mutate(prop_delay = arr_delay / sum(arr_delay)) %>% 
  select(year:day, dest, arr_delay, prop_delay)
#> Source: local data frame [131,106 x 6]
#> Groups: dest [77]
#> 
#>    year month   day  dest arr_delay prop_delay
#>   <int> <int> <int> <chr>     <dbl>      <dbl>
#> 1  2013     1     1   IAH        11   1.11e-04
#> 2  2013     1     1   IAH        20   2.01e-04
#> 3  2013     1     1   MIA        33   2.35e-04
#> 4  2013     1     1   ORD        12   4.24e-05
#> 5  2013     1     1   FLL        19   9.38e-05
#> 6  2013     1     1   ORD         8   2.83e-05
#> # ... with 1.311e+05 more rows
LS0tDQp0aXRsZTogIsr9vt3Xqru7Ig0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyDEv8K8DQorIDEgx7DM4de8sbgNCiAgICArIDEuMSDU2MjrsagNCiAgICArIDEuMiBgZmxpZ2h0c2Agyv2+3byvDQogICAgKyAxLjMgyv2+3cDg0M296cncDQogICAgKyAxLjQgYGRwbHlyYCC7+bShDQorIDIg08MgYGZpbHRlcigpYCDJuNGh0NANCiAgICArIDIuMSCwtLj4tqi1xMLfvK3F0LbPybjRobP2t/u6z9Kqx/O1xNfTyv2+3byvDQogICAgKyAyLjIgttTEs7j2seTBv9GhyKHBvbj2u/LS1MnPtcTWtQ0KICAgICsgMi4zIMixyqfWtQ0KICAgICsgMi40IGBiZXR3ZWVuKClgDQorIDMg08MgYGFycmFuZ2UoKWAgxcXB0NDQDQorIDQg08MgYHNlbGVjdCgpYCDJuNGhwdANCiAgICArIDQuMSC7+bG+08O3qA0KICAgICsgNC4yIEhlbHBlciBGdW5jdGlvbnMNCiAgICArIDQuMyDA+9PDIGBldmVyeXRoaW5nKClgIL2rwdDSxrW91+7HsMPmDQogICAgKyA0LjQgYHJlbmFtZSgpYCC6r8r9DQorIDUg08MgYG11dGF0ZSgpYCDM7bzTwdANCiAgICArIDUuMSC7+bG+08O3qA0KICAgICsgNS4yIL/J0tTTw9PavMbL49DCseTBv7XEz/LBv7uv1MvL47f7DQorIDYg08MgYHN1bW1hcmlzZSgpYCC8xsvjt9bX6c2zvMbBvw0KICAgICsgNi4xIGBncm91cF9ieSgpYCC6zSBgc3VtbWFyaXNlKClgIMGqus/KudPDo6y8xsvjt9bX6c2zvMbBvw0KICAgICsgNi4yILnctcCy2df3t/sgYCU+JWANCiAgICArIDYuMyDIscqn1rUNCiAgICArIDYuNCC8xsr9o6hgY291bnRgo6kNCiAgICArIDYuNSC+27rPzbO8xrqvyv0NCiAgICArIDYuNiDSwL7dtuC49rHkwb+9+NDQt9bX6Q0KICAgICsgNi43IMihz/u31tfpDQorIDcgt9bX6bHku7ujqGBtdXRhdGUoKWAsIGBmaWx0ZXIoKWCjqQ0KDQojIDEgx7DM4de8sbgNCiMjIDEuMSDU2MjrsPwNCmBgYHtyfQ0KbGlicmFyeShueWNmbGlnaHRzMTMpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KDQojIyAxLjIgYGZsaWdodHNgIMr9vt28ryAgDQorIGBmbGlnaHRzYCDK/b7dvK/S1CBgdGliYmxlYCDQzsq9tOa0og0KYGBge3J9DQpmbGlnaHRzDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMzM2LDc3NiChwSAxOQ0KIz4gICAgeWVhciBtb250aCAgIGRheSBkZXBfdGltZSBzY2hlZF9kZXBfdGltZSBkZXBfZGVsYXkgYXJyX3RpbWUNCiM+ICAgPGludD4gPGludD4gPGludD4gICAgPGludD4gICAgICAgICAgPGludD4gICAgIDxkYmw+ICAgIDxpbnQ+DQojPiAxICAyMDEzICAgICAxICAgICAxICAgICAgNTE3ICAgICAgICAgICAgNTE1ICAgICAgICAgMiAgICAgIDgzMA0KIz4gMiAgMjAxMyAgICAgMSAgICAgMSAgICAgIDUzMyAgICAgICAgICAgIDUyOSAgICAgICAgIDQgICAgICA4NTANCiM+IDMgIDIwMTMgICAgIDEgICAgIDEgICAgICA1NDIgICAgICAgICAgICA1NDAgICAgICAgICAyICAgICAgOTIzDQojPiA0ICAyMDEzICAgICAxICAgICAxICAgICAgNTQ0ICAgICAgICAgICAgNTQ1ICAgICAgICAtMSAgICAgMTAwNA0KIz4gNSAgMjAxMyAgICAgMSAgICAgMSAgICAgIDU1NCAgICAgICAgICAgIDYwMCAgICAgICAgLTYgICAgICA4MTINCiM+IDYgIDIwMTMgICAgIDEgICAgIDEgICAgICA1NTQgICAgICAgICAgICA1NTggICAgICAgIC00ICAgICAgNzQwDQojPiAjIC4uLiB3aXRoIDMuMzY4ZSswNSBtb3JlIHJvd3MsIGFuZCAxMiBtb3JlIHZhcmlhYmxlczoNCiM+ICMgICBzY2hlZF9hcnJfdGltZSA8aW50PiwgYXJyX2RlbGF5IDxkYmw+LCBjYXJyaWVyIDxjaHI+LCBmbGlnaHQgPGludD4sDQojPiAjICAgdGFpbG51bSA8Y2hyPiwgb3JpZ2luIDxjaHI+LCBkZXN0IDxjaHI+LCBhaXJfdGltZSA8ZGJsPiwNCiM+ICMgICBkaXN0YW5jZSA8ZGJsPiwgaG91ciA8ZGJsPiwgbWludXRlIDxkYmw+LCB0aW1lX2hvdXIgPGR0dG0+DQpgYGANCg0KKyDKudPDIGBWaWV3YCC/ydLUuduy7M3q1fu1xCBgZmxpZ2h0c2Agyv2+3byvICANCmBgYA0KVmlldyhmbGlnaHRzKQ0KYGBgDQoNCiMjIDEuMyDK/b7dwODQzb3pydwNCg0KKyBgaW50YCBzdGFuZHMgZm9yIGludGVnZXJzLg0KDQorIGBkYmxgIHN0YW5kcyBmb3IgZG91Ymxlcywgb3IgcmVhbCBudW1iZXJzLg0KDQorIGBjaHJgIHN0YW5kcyBmb3IgY2hhcmFjdGVyIHZlY3RvcnMsIG9yIHN0cmluZ3MuDQoNCisgYGR0dG1gIHN0YW5kcyBmb3IgZGF0ZS10aW1lcyAoYSBkYXRlICsgYSB0aW1lKS4NCg0KKyBgbGdsYCBzdGFuZHMgZm9yIGxvZ2ljYWwsIHZlY3RvcnMgdGhhdCBjb250YWluIG9ubHkgVFJVRSBvciBGQUxTRS4NCg0KKyBgZmN0cmAgc3RhbmRzIGZvciBmYWN0b3JzLCB3aGljaCBSIHVzZXMgdG8gcmVwcmVzZW50IGNhdGVnb3JpY2FsIHZhcmlhYmxlcyB3aXRoIGZpeGVkIHBvc3NpYmxlIHZhbHVlcy4NCg0KKyBgZGF0ZWAgc3RhbmRzIGZvciBkYXRlcy4NCg0KIyMgMS40IGBkcGx5cmAgu/m0oQ0KvdPPwsC0o6y9q7vhvdO0pbW9NdbWusvQxLXEIGBkcGx5cmAguq/K/Q0KDQorIFBpY2sgb2JzZXJ2YXRpb25zIGJ5IHRoZWlyIHZhbHVlcyBgZmlsdGVyKClgLg0KDQorIFJlb3JkZXIgdGhlIHJvd3MgYGFycmFuZ2UoKWAuDQoNCisgUGljayB2YXJpYWJsZXMgYnkgdGhlaXIgbmFtZXMgYHNlbGVjdCgpYC4NCg0KKyBDcmVhdGUgbmV3IHZhcmlhYmxlcyB3aXRoIGZ1bmN0aW9ucyBvZiBleGlzdGluZyB2YXJpYWJsZXMgYG11dGF0ZSgpYC4NCg0KKyBDb2xsYXBzZSBtYW55IHZhbHVlcyBkb3duIHRvIGEgc2luZ2xlIHN1bW1hcnkgYHN1bW1hcmlzZSgpYC4NCg0KIyAyINPDIGBmaWx0ZXIoKWAgybjRodDQICANCiMjIDIuMSCwtLj4tqi1xMLfvK3F0LbPybjRobP2t/u6z9Kqx/O1xNfTyv2+3byvLCDA4MvG09ogYmFzZTo6c3Vic2V0KCkguq/K/Q0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgbW9udGggPT0gMSwgZGF5ID09IDEpDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogODQyIKHBIDE5DQojPiAgICB5ZWFyIG1vbnRoICAgZGF5IGRlcF90aW1lIHNjaGVkX2RlcF90aW1lIGRlcF9kZWxheSBhcnJfdGltZQ0KIz4gICA8aW50PiA8aW50PiA8aW50PiAgICA8aW50PiAgICAgICAgICA8aW50PiAgICAgPGRibD4gICAgPGludD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICAgICA1MTcgICAgICAgICAgICA1MTUgICAgICAgICAyICAgICAgODMwDQojPiAyICAyMDEzICAgICAxICAgICAxICAgICAgNTMzICAgICAgICAgICAgNTI5ICAgICAgICAgNCAgICAgIDg1MA0KIz4gMyAgMjAxMyAgICAgMSAgICAgMSAgICAgIDU0MiAgICAgICAgICAgIDU0MCAgICAgICAgIDIgICAgICA5MjMNCiM+IDQgIDIwMTMgICAgIDEgICAgIDEgICAgICA1NDQgICAgICAgICAgICA1NDUgICAgICAgIC0xICAgICAxMDA0DQojPiA1ICAyMDEzICAgICAxICAgICAxICAgICAgNTU0ICAgICAgICAgICAgNjAwICAgICAgICAtNiAgICAgIDgxMg0KIz4gNiAgMjAxMyAgICAgMSAgICAgMSAgICAgIDU1NCAgICAgICAgICAgIDU1OCAgICAgICAgLTQgICAgICA3NDANCiM+ICMgLi4uIHdpdGggODM2IG1vcmUgcm93cywgYW5kIDEyIG1vcmUgdmFyaWFibGVzOiBzY2hlZF9hcnJfdGltZSA8aW50PiwNCiM+ICMgICBhcnJfZGVsYXkgPGRibD4sIGNhcnJpZXIgPGNocj4sIGZsaWdodCA8aW50PiwgdGFpbG51bSA8Y2hyPiwNCiM+ICMgICBvcmlnaW4gPGNocj4sIGRlc3QgPGNocj4sIGFpcl90aW1lIDxkYmw+LCBkaXN0YW5jZSA8ZGJsPiwgaG91ciA8ZGJsPiwNCiM+ICMgICBtaW51dGUgPGRibD4sIHRpbWVfaG91ciA8ZHR0bT4NCmBgYA0KDQpgYGB7cn0NCihkZWMyNSA8LSBmaWx0ZXIoZmxpZ2h0cywgbW9udGggPT0gMTIsIGRheSA9PSAyNSkpDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogNzE5IKHBIDE5DQojPiAgICB5ZWFyIG1vbnRoICAgZGF5IGRlcF90aW1lIHNjaGVkX2RlcF90aW1lIGRlcF9kZWxheSBhcnJfdGltZQ0KIz4gICA8aW50PiA8aW50PiA8aW50PiAgICA8aW50PiAgICAgICAgICA8aW50PiAgICAgPGRibD4gICAgPGludD4NCiM+IDEgIDIwMTMgICAgMTIgICAgMjUgICAgICA0NTYgICAgICAgICAgICA1MDAgICAgICAgIC00ICAgICAgNjQ5DQojPiAyICAyMDEzICAgIDEyICAgIDI1ICAgICAgNTI0ICAgICAgICAgICAgNTE1ICAgICAgICAgOSAgICAgIDgwNQ0KIz4gMyAgMjAxMyAgICAxMiAgICAyNSAgICAgIDU0MiAgICAgICAgICAgIDU0MCAgICAgICAgIDIgICAgICA4MzINCiM+IDQgIDIwMTMgICAgMTIgICAgMjUgICAgICA1NDYgICAgICAgICAgICA1NTAgICAgICAgIC00ICAgICAxMDIyDQojPiA1ICAyMDEzICAgIDEyICAgIDI1ICAgICAgNTU2ICAgICAgICAgICAgNjAwICAgICAgICAtNCAgICAgIDczMA0KIz4gNiAgMjAxMyAgICAxMiAgICAyNSAgICAgIDU1NyAgICAgICAgICAgIDYwMCAgICAgICAgLTMgICAgICA3NDMNCiM+ICMgLi4uIHdpdGggNzEzIG1vcmUgcm93cywgYW5kIDEyIG1vcmUgdmFyaWFibGVzOiBzY2hlZF9hcnJfdGltZSA8aW50PiwNCiM+ICMgICBhcnJfZGVsYXkgPGRibD4sIGNhcnJpZXIgPGNocj4sIGZsaWdodCA8aW50PiwgdGFpbG51bSA8Y2hyPiwNCiM+ICMgICBvcmlnaW4gPGNocj4sIGRlc3QgPGNocj4sIGFpcl90aW1lIDxkYmw+LCBkaXN0YW5jZSA8ZGJsPiwgaG91ciA8ZGJsPiwNCiM+ICMgICBtaW51dGUgPGRibD4sIHRpbWVfaG91ciA8ZHR0bT4NCmBgYA0KDQojIyAyLjIgttTEs7j2seTBv9GhyKHBvbj2u/LS1MnPtcTWtQ0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgbW9udGggPT0gMTEgfCBtb250aCA9PSAxMikNCmBgYA0KYGBge3J9DQpmaWx0ZXIoZmxpZ2h0cywgbW9udGggJWluJSBjKDExLCAxMikpDQpgYGANCg0KIyMgMi4zIMixyqfWtQ0KKyBgTkFgICihsG5vdCBhdmFpbGFibGVzobEpILT6se3Iscqn1rWjrNTavMbL49bQ09ChsLSryL7Q1KGxo7q21CBgTkFgIL340NDIztListnX96Ostry74be1u9ggYE5BYKGjDQpgYGB7cn0NCk5BID4gNQ0KYGBgDQpgYGB7cn0NCjEwID09IE5BDQpgYGANCmBgYHtyfQ0KTkEgKyAxMA0KYGBgDQpgYGB7cn0NCk5BIC8gMg0KYGBgDQpgYGB7cn0NCk5BID09IE5BDQpgYGANCmBgYHtyfQ0KeCA8LSBOQQ0KeSA8LSBOQQ0KeCA9PSB5DQpgYGANCg0KKyDTwyBgaXMubmEoKWAgxdC2z8rHt/HOqsixyqfWtQ0KYGBge3J9DQppcy5uYSh4KQ0KYGBgDQoNCmBgYHtyfQ0KZGYgPC0gdGliYmxlKHggPSBjKDEsIE5BLCAzKSkNCmZpbHRlcihkZiwgeCA+IDEpDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMSChwSAxDQojPiAgICAgICB4DQojPiAgIDxkYmw+DQojPiAxICAgICAzDQpgYGANCg0KKyBgZmlsdGVyKClgILvhxcWz/SBgRmFsc2VgILrNIGBOQWAgtcTQ0KOsvfa99re1u9i94bn7zqogYFRydWVgILXE0NCho8jnufvP69KqsaPB9MixyqfWtaOs0OjSqr340NDP1Mq9yfnD9w0KYGBge3J9DQpmaWx0ZXIoZGYsIGlzLm5hKHgpIHwgeCA+IDEpDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMiChwSAxDQojPiAgICAgICB4DQojPiAgIDxkYmw+DQojPiAxICAgIE5BDQojPiAyICAgICAzDQpgYGANCg0KIyMgMi40IGBiZXR3ZWVuKClgDQpgYGB7cn0NCmRmIDwtIHRpYmJsZSh4ID0gYygxLCAyLCAyLCAzLCA0KSkNCmZpbHRlcihkZiwgYmV0d2Vlbih4LCAxLCAzKSkNCmBgYA0KYGBgDQojPiAjIEEgdGliYmxlOiA0IKHBIDENCiM+ICAgICAgIHgNCiM+ICAgPGRibD4NCiM+IDEgICAgIDENCiM+IDIgICAgIDINCiM+IDMgICAgIDINCiM+IDQgICAgIDMNCmBgYA0KDQojIDMg08MgYGFycmFuZ2UoKWAgxcXB0NDQDQorILC0uPi2qLXEwdDD+9LAtM621NDQvfjQ0MXF0PINCmBgYHtyfQ0KYXJyYW5nZShmbGlnaHRzLCB5ZWFyLCBtb250aCwgZGF5KQ0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDMzNiw3NzYgocEgMTkNCiM+ICAgIHllYXIgbW9udGggICBkYXkgZGVwX3RpbWUgc2NoZWRfZGVwX3RpbWUgZGVwX2RlbGF5IGFycl90aW1lDQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+ICAgIDxpbnQ+ICAgICAgICAgIDxpbnQ+ICAgICA8ZGJsPiAgICA8aW50Pg0KIz4gMSAgMjAxMyAgICAgMSAgICAgMSAgICAgIDUxNyAgICAgICAgICAgIDUxNSAgICAgICAgIDIgICAgICA4MzANCiM+IDIgIDIwMTMgICAgIDEgICAgIDEgICAgICA1MzMgICAgICAgICAgICA1MjkgICAgICAgICA0ICAgICAgODUwDQojPiAzICAyMDEzICAgICAxICAgICAxICAgICAgNTQyICAgICAgICAgICAgNTQwICAgICAgICAgMiAgICAgIDkyMw0KIz4gNCAgMjAxMyAgICAgMSAgICAgMSAgICAgIDU0NCAgICAgICAgICAgIDU0NSAgICAgICAgLTEgICAgIDEwMDQNCiM+IDUgIDIwMTMgICAgIDEgICAgIDEgICAgICA1NTQgICAgICAgICAgICA2MDAgICAgICAgIC02ICAgICAgODEyDQojPiA2ICAyMDEzICAgICAxICAgICAxICAgICAgNTU0ICAgICAgICAgICAgNTU4ICAgICAgICAtNCAgICAgIDc0MA0KIz4gIyAuLi4gd2l0aCAzLjM2OGUrMDUgbW9yZSByb3dzLCBhbmQgMTIgbW9yZSB2YXJpYWJsZXM6DQojPiAjICAgc2NoZWRfYXJyX3RpbWUgPGludD4sIGFycl9kZWxheSA8ZGJsPiwgY2FycmllciA8Y2hyPiwgZmxpZ2h0IDxpbnQ+LA0KIz4gIyAgIHRhaWxudW0gPGNocj4sIG9yaWdpbiA8Y2hyPiwgZGVzdCA8Y2hyPiwgYWlyX3RpbWUgPGRibD4sDQojPiAjICAgZGlzdGFuY2UgPGRibD4sIGhvdXIgPGRibD4sIG1pbnV0ZSA8ZGJsPiwgdGltZV9ob3VyIDxkdHRtPg0KYGBgDQoNCisg08MgYGRlc2MoKWAgvfjQ0L210PLFxcHQDQpgYGB7cn0NCmFycmFuZ2UoZmxpZ2h0cywgZGVzYyhhcnJfZGVsYXkpKQ0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDMzNiw3NzYgocEgMTkNCiM+ICAgIHllYXIgbW9udGggICBkYXkgZGVwX3RpbWUgc2NoZWRfZGVwX3RpbWUgZGVwX2RlbGF5IGFycl90aW1lDQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+ICAgIDxpbnQ+ICAgICAgICAgIDxpbnQ+ICAgICA8ZGJsPiAgICA8aW50Pg0KIz4gMSAgMjAxMyAgICAgMSAgICAgOSAgICAgIDY0MSAgICAgICAgICAgIDkwMCAgICAgIDEzMDEgICAgIDEyNDINCiM+IDIgIDIwMTMgICAgIDYgICAgMTUgICAgIDE0MzIgICAgICAgICAgIDE5MzUgICAgICAxMTM3ICAgICAxNjA3DQojPiAzICAyMDEzICAgICAxICAgIDEwICAgICAxMTIxICAgICAgICAgICAxNjM1ICAgICAgMTEyNiAgICAgMTIzOQ0KIz4gNCAgMjAxMyAgICAgOSAgICAyMCAgICAgMTEzOSAgICAgICAgICAgMTg0NSAgICAgIDEwMTQgICAgIDE0NTcNCiM+IDUgIDIwMTMgICAgIDcgICAgMjIgICAgICA4NDUgICAgICAgICAgIDE2MDAgICAgICAxMDA1ICAgICAxMDQ0DQojPiA2ICAyMDEzICAgICA0ICAgIDEwICAgICAxMTAwICAgICAgICAgICAxOTAwICAgICAgIDk2MCAgICAgMTM0Mg0KIz4gIyAuLi4gd2l0aCAzLjM2OGUrMDUgbW9yZSByb3dzLCBhbmQgMTIgbW9yZSB2YXJpYWJsZXM6DQojPiAjICAgc2NoZWRfYXJyX3RpbWUgPGludD4sIGFycl9kZWxheSA8ZGJsPiwgY2FycmllciA8Y2hyPiwgZmxpZ2h0IDxpbnQ+LA0KIz4gIyAgIHRhaWxudW0gPGNocj4sIG9yaWdpbiA8Y2hyPiwgZGVzdCA8Y2hyPiwgYWlyX3RpbWUgPGRibD4sDQojPiAjICAgZGlzdGFuY2UgPGRibD4sIGhvdXIgPGRibD4sIG1pbnV0ZSA8ZGJsPiwgdGltZV9ob3VyIDxkdHRtPg0KYGBgDQoNCisgyLHKp9a1vau74bG7t8XWw9Tayv2+3byvtcTEqc6yDQpgYGB7cn0NCmRmIDwtIHRpYmJsZSh4ID0gYyg1LCAyLCBOQSkpDQphcnJhbmdlKGRmLCB4KQ0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDMgocEgMQ0KIz4gICAgICAgeA0KIz4gICA8ZGJsPg0KIz4gMSAgICAgMg0KIz4gMiAgICAgNQ0KIz4gMyAgICBOQQ0KYGBgDQpgYGB7cn0NCmFycmFuZ2UoZGYsIGRlc2MoeCkpDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMyChwSAxDQojPiAgICAgICB4DQojPiAgIDxkYmw+DQojPiAxICAgICA1DQojPiAyICAgICAyDQojPiAzICAgIE5BDQpgYGANCg0KIyA0INPDIGBzZWxlY3QoKWAgybjRocHQDQojIyA0LjEgu/mxvtPDt6gNCisg0aHU8XllYXKhom1vbnRooaJkYXnB0A0KYGBge3J9DQpzZWxlY3QoZmxpZ2h0cywgeWVhciwgbW9udGgsIGRheSkNCmBgYA0KYGBgDQojPiAjIEEgdGliYmxlOiAzMzYsNzc2IKHBIDMNCiM+ICAgIHllYXIgbW9udGggICBkYXkNCiM+ICAgPGludD4gPGludD4gPGludD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDENCiM+IDIgIDIwMTMgICAgIDEgICAgIDENCiM+IDMgIDIwMTMgICAgIDEgICAgIDENCiM+IDQgIDIwMTMgICAgIDEgICAgIDENCiM+IDUgIDIwMTMgICAgIDEgICAgIDENCiM+IDYgIDIwMTMgICAgIDEgICAgIDENCiM+ICMgLi4uIHdpdGggMy4zNjhlKzA1IG1vcmUgcm93cw0KYGBgDQoNCisg0aHU8XllYXK6zWRhedauvOS1xMHQo6iw/MCoo6kNCmBgYHtyfQ0Kc2VsZWN0KGZsaWdodHMsIHllYXI6ZGF5KQ0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDMzNiw3NzYgocEgMw0KIz4gICAgeWVhciBtb250aCAgIGRheQ0KIz4gICA8aW50PiA8aW50PiA8aW50Pg0KIz4gMSAgMjAxMyAgICAgMSAgICAgMQ0KIz4gMiAgMjAxMyAgICAgMSAgICAgMQ0KIz4gMyAgMjAxMyAgICAgMSAgICAgMQ0KIz4gNCAgMjAxMyAgICAgMSAgICAgMQ0KIz4gNSAgMjAxMyAgICAgMSAgICAgMQ0KIz4gNiAgMjAxMyAgICAgMSAgICAgMQ0KIz4gIyAuLi4gd2l0aCAzLjM2OGUrMDUgbW9yZSByb3dzDQpgYGANCg0KKyDRodTxs/15ZWFyus1kYXnWrrzktcTB0NLUzeK1xMv509DB0KOosPzAqKOpDQpgYGB7cn0NCnNlbGVjdChmbGlnaHRzLCAtKHllYXI6ZGF5KSkNCmBgYA0KYGBgDQojPiAjIEEgdGliYmxlOiAzMzYsNzc2IKHBIDE2DQojPiAgIGRlcF90aW1lIHNjaGVkX2RlcF90aW1lIGRlcF9kZWxheSBhcnJfdGltZSBzY2hlZF9hcnJfdGltZSBhcnJfZGVsYXkNCiM+ICAgICAgPGludD4gICAgICAgICAgPGludD4gICAgIDxkYmw+ICAgIDxpbnQ+ICAgICAgICAgIDxpbnQ+ICAgICA8ZGJsPg0KIz4gMSAgICAgIDUxNyAgICAgICAgICAgIDUxNSAgICAgICAgIDIgICAgICA4MzAgICAgICAgICAgICA4MTkgICAgICAgIDExDQojPiAyICAgICAgNTMzICAgICAgICAgICAgNTI5ICAgICAgICAgNCAgICAgIDg1MCAgICAgICAgICAgIDgzMCAgICAgICAgMjANCiM+IDMgICAgICA1NDIgICAgICAgICAgICA1NDAgICAgICAgICAyICAgICAgOTIzICAgICAgICAgICAgODUwICAgICAgICAzMw0KIz4gNCAgICAgIDU0NCAgICAgICAgICAgIDU0NSAgICAgICAgLTEgICAgIDEwMDQgICAgICAgICAgIDEwMjIgICAgICAgLTE4DQojPiA1ICAgICAgNTU0ICAgICAgICAgICAgNjAwICAgICAgICAtNiAgICAgIDgxMiAgICAgICAgICAgIDgzNyAgICAgICAtMjUNCiM+IDYgICAgICA1NTQgICAgICAgICAgICA1NTggICAgICAgIC00ICAgICAgNzQwICAgICAgICAgICAgNzI4ICAgICAgICAxMg0KIz4gIyAuLi4gd2l0aCAzLjM2OGUrMDUgbW9yZSByb3dzLCBhbmQgMTAgbW9yZSB2YXJpYWJsZXM6IGNhcnJpZXIgPGNocj4sDQojPiAjICAgZmxpZ2h0IDxpbnQ+LCB0YWlsbnVtIDxjaHI+LCBvcmlnaW4gPGNocj4sIGRlc3QgPGNocj4sIGFpcl90aW1lIDxkYmw+LA0KIz4gIyAgIGRpc3RhbmNlIDxkYmw+LCBob3VyIDxkYmw+LCBtaW51dGUgPGRibD4sIHRpbWVfaG91ciA8ZHR0bT4NCmBgYA0KDQojIyA0LjIgSGVscGVyIEZ1bmN0aW9ucw0KKyBgc3RhcnRzX3dpdGgoeCwgaWdub3JlLmNhc2UgPSBUUlVFKWA6IG5hbWVzIHN0YXJ0cyB3aXRoIHguICANCg0KKyBgZW5kc193aXRoKHgsIGlnbm9yZS5jYXNlID0gVFJVRSlgOiBuYW1lcyBlbmRzIGluIHguICANCg0KKyBgY29udGFpbnMoeCwgaWdub3JlLmNhc2UgPSBUUlVFKWA6IHNlbGVjdHMgYWxsIHZhcmlhYmxlcyB3aG9zZSBuYW1lIGNvbnRhaW5zIHguICANCg0KKyBgbWF0Y2hlcyh4LCBpZ25vcmUuY2FzZSA9IFRSVUUpYDogc2VsZWN0cyBhbGwgdmFyaWFibGVzIHdob3NlIG5hbWUgbWF0Y2hlcyB0aGUgcmVndWxhciBleHByZXNzaW9uIHguICANCg0KKyBgbnVtX3JhbmdlKCJ4IiwgMTo1LCB3aWR0aCA9IDIpYDogc2VsZWN0cyBhbGwgdmFyaWFibGVzIChudW1lcmljYWxseSkgZnJvbSB4MDEgdG8geDA1LiAgDQoNCisgYG9uZV9vZigieCIsICJ5IiwgInoiKWA6IHNlbGVjdHMgdmFyaWFibGVzIHByb3ZpZGVkIGluIGEgY2hhcmFjdGVyIHZlY3Rvci4gIA0KDQorIGBldmVyeXRoaW5nKClgOiBzZWxlY3RzIGFsbCB2YXJpYWJsZXMuDQoNCiMjIDQuMyDA+9PDIGBldmVyeXRoaW5nKClgIL2rwdDSxrW91+7HsMPmDQpgYGB7cn0NCnNlbGVjdChmbGlnaHRzLCB0aW1lX2hvdXIsIGFpcl90aW1lLCBldmVyeXRoaW5nKCkpDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMzM2LDc3NiChwSAxOQ0KIz4gICAgICAgICAgICAgdGltZV9ob3VyIGFpcl90aW1lICB5ZWFyIG1vbnRoICAgZGF5IGRlcF90aW1lIHNjaGVkX2RlcF90aW1lDQojPiAgICAgICAgICAgICAgICA8ZHR0bT4gICAgPGRibD4gPGludD4gPGludD4gPGludD4gICAgPGludD4gICAgICAgICAgPGludD4NCiM+IDEgMjAxMy0wMS0wMSAwNTowMDowMCAgICAgIDIyNyAgMjAxMyAgICAgMSAgICAgMSAgICAgIDUxNyAgICAgICAgICAgIDUxNQ0KIz4gMiAyMDEzLTAxLTAxIDA1OjAwOjAwICAgICAgMjI3ICAyMDEzICAgICAxICAgICAxICAgICAgNTMzICAgICAgICAgICAgNTI5DQojPiAzIDIwMTMtMDEtMDEgMDU6MDA6MDAgICAgICAxNjAgIDIwMTMgICAgIDEgICAgIDEgICAgICA1NDIgICAgICAgICAgICA1NDANCiM+IDQgMjAxMy0wMS0wMSAwNTowMDowMCAgICAgIDE4MyAgMjAxMyAgICAgMSAgICAgMSAgICAgIDU0NCAgICAgICAgICAgIDU0NQ0KIz4gNSAyMDEzLTAxLTAxIDA2OjAwOjAwICAgICAgMTE2ICAyMDEzICAgICAxICAgICAxICAgICAgNTU0ICAgICAgICAgICAgNjAwDQojPiA2IDIwMTMtMDEtMDEgMDU6MDA6MDAgICAgICAxNTAgIDIwMTMgICAgIDEgICAgIDEgICAgICA1NTQgICAgICAgICAgICA1NTgNCiM+ICMgLi4uIHdpdGggMy4zNjhlKzA1IG1vcmUgcm93cywgYW5kIDEyIG1vcmUgdmFyaWFibGVzOiBkZXBfZGVsYXkgPGRibD4sDQojPiAjICAgYXJyX3RpbWUgPGludD4sIHNjaGVkX2Fycl90aW1lIDxpbnQ+LCBhcnJfZGVsYXkgPGRibD4sIGNhcnJpZXIgPGNocj4sDQojPiAjICAgZmxpZ2h0IDxpbnQ+LCB0YWlsbnVtIDxjaHI+LCBvcmlnaW4gPGNocj4sIGRlc3QgPGNocj4sIGRpc3RhbmNlIDxkYmw+LA0KIz4gIyAgIGhvdXIgPGRibD4sIG1pbnV0ZSA8ZGJsPg0KYGBgDQoNCiMjIDQuNCBgcmVuYW1lKClgILqvyv0NCmBgYHtyfQ0KcmVuYW1lKGZsaWdodHMsIHRhaWxfbnVtID0gdGFpbG51bSkNCmBgYA0KYGBgDQojPiAjIEEgdGliYmxlOiAzMzYsNzc2IKHBIDE5DQojPiAgICB5ZWFyIG1vbnRoICAgZGF5IGRlcF90aW1lIHNjaGVkX2RlcF90aW1lIGRlcF9kZWxheSBhcnJfdGltZQ0KIz4gICA8aW50PiA8aW50PiA8aW50PiAgICA8aW50PiAgICAgICAgICA8aW50PiAgICAgPGRibD4gICAgPGludD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICAgICA1MTcgICAgICAgICAgICA1MTUgICAgICAgICAyICAgICAgODMwDQojPiAyICAyMDEzICAgICAxICAgICAxICAgICAgNTMzICAgICAgICAgICAgNTI5ICAgICAgICAgNCAgICAgIDg1MA0KIz4gMyAgMjAxMyAgICAgMSAgICAgMSAgICAgIDU0MiAgICAgICAgICAgIDU0MCAgICAgICAgIDIgICAgICA5MjMNCiM+IDQgIDIwMTMgICAgIDEgICAgIDEgICAgICA1NDQgICAgICAgICAgICA1NDUgICAgICAgIC0xICAgICAxMDA0DQojPiA1ICAyMDEzICAgICAxICAgICAxICAgICAgNTU0ICAgICAgICAgICAgNjAwICAgICAgICAtNiAgICAgIDgxMg0KIz4gNiAgMjAxMyAgICAgMSAgICAgMSAgICAgIDU1NCAgICAgICAgICAgIDU1OCAgICAgICAgLTQgICAgICA3NDANCiM+ICMgLi4uIHdpdGggMy4zNjhlKzA1IG1vcmUgcm93cywgYW5kIDEyIG1vcmUgdmFyaWFibGVzOg0KIz4gIyAgIHNjaGVkX2Fycl90aW1lIDxpbnQ+LCBhcnJfZGVsYXkgPGRibD4sIGNhcnJpZXIgPGNocj4sIGZsaWdodCA8aW50PiwNCiM+ICMgICB0YWlsX251bSA8Y2hyPiwgb3JpZ2luIDxjaHI+LCBkZXN0IDxjaHI+LCBhaXJfdGltZSA8ZGJsPiwNCiM+ICMgICBkaXN0YW5jZSA8ZGJsPiwgaG91ciA8ZGJsPiwgbWludXRlIDxkYmw+LCB0aW1lX2hvdXIgPGR0dG0+DQpgYGANCg0KIyA1INPDIGBtdXRhdGUoKWAgzO2808HQDQojIyA1LjEgu/mxvtPDt6gNCisgttTS0dPQwdC9+NDQyv2+3dTLy+OyosztvNPOqtDCwdANCmBgYHtyfQ0KZmxpZ2h0c19zbWwgPC0gc2VsZWN0KGZsaWdodHMsIA0KICB5ZWFyOmRheSwgDQogIGVuZHNfd2l0aCgiZGVsYXkiKSwgDQogIGRpc3RhbmNlLCANCiAgYWlyX3RpbWUNCikNCg0KbXV0YXRlKGZsaWdodHNfc21sLA0KICBnYWluID0gYXJyX2RlbGF5IC0gZGVwX2RlbGF5LA0KICBzcGVlZCA9IGRpc3RhbmNlIC8gYWlyX3RpbWUgKiA2MA0KKQ0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDMzNiw3NzYgocEgOQ0KIz4gICAgeWVhciBtb250aCAgIGRheSBkZXBfZGVsYXkgYXJyX2RlbGF5IGRpc3RhbmNlIGFpcl90aW1lICBnYWluIHNwZWVkDQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+ICAgICA8ZGJsPiAgICAgPGRibD4gICAgPGRibD4gICAgPGRibD4gPGRibD4gPGRibD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICAgICAgICAyICAgICAgICAxMSAgICAgMTQwMCAgICAgIDIyNyAgICAgOSAgIDM3MA0KIz4gMiAgMjAxMyAgICAgMSAgICAgMSAgICAgICAgIDQgICAgICAgIDIwICAgICAxNDE2ICAgICAgMjI3ICAgIDE2ICAgMzc0DQojPiAzICAyMDEzICAgICAxICAgICAxICAgICAgICAgMiAgICAgICAgMzMgICAgIDEwODkgICAgICAxNjAgICAgMzEgICA0MDgNCiM+IDQgIDIwMTMgICAgIDEgICAgIDEgICAgICAgIC0xICAgICAgIC0xOCAgICAgMTU3NiAgICAgIDE4MyAgIC0xNyAgIDUxNw0KIz4gNSAgMjAxMyAgICAgMSAgICAgMSAgICAgICAgLTYgICAgICAgLTI1ICAgICAgNzYyICAgICAgMTE2ICAgLTE5ICAgMzk0DQojPiA2ICAyMDEzICAgICAxICAgICAxICAgICAgICAtNCAgICAgICAgMTIgICAgICA3MTkgICAgICAxNTAgICAgMTYgICAyODgNCiM+ICMgLi4uIHdpdGggMy4zNjhlKzA1IG1vcmUgcm93cw0KYGBgDQoNCisgv8nS1NTazazSu9PvvuTW0LbUuNXU9rzTtcTB0L340NCy2df3DQpgYGB7cn0NCm11dGF0ZShmbGlnaHRzX3NtbCwNCiAgZ2FpbiA9IGFycl9kZWxheSAtIGRlcF9kZWxheSwNCiAgaG91cnMgPSBhaXJfdGltZSAvIDYwLA0KICBnYWluX3Blcl9ob3VyID0gZ2FpbiAvIGhvdXJzDQopDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMzM2LDc3NiChwSAxMA0KIz4gICAgeWVhciBtb250aCAgIGRheSBkZXBfZGVsYXkgYXJyX2RlbGF5IGRpc3RhbmNlIGFpcl90aW1lICBnYWluIGhvdXJzDQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+ICAgICA8ZGJsPiAgICAgPGRibD4gICAgPGRibD4gICAgPGRibD4gPGRibD4gPGRibD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICAgICAgICAyICAgICAgICAxMSAgICAgMTQwMCAgICAgIDIyNyAgICAgOSAgMy43OA0KIz4gMiAgMjAxMyAgICAgMSAgICAgMSAgICAgICAgIDQgICAgICAgIDIwICAgICAxNDE2ICAgICAgMjI3ICAgIDE2ICAzLjc4DQojPiAzICAyMDEzICAgICAxICAgICAxICAgICAgICAgMiAgICAgICAgMzMgICAgIDEwODkgICAgICAxNjAgICAgMzEgIDIuNjcNCiM+IDQgIDIwMTMgICAgIDEgICAgIDEgICAgICAgIC0xICAgICAgIC0xOCAgICAgMTU3NiAgICAgIDE4MyAgIC0xNyAgMy4wNQ0KIz4gNSAgMjAxMyAgICAgMSAgICAgMSAgICAgICAgLTYgICAgICAgLTI1ICAgICAgNzYyICAgICAgMTE2ICAgLTE5ICAxLjkzDQojPiA2ICAyMDEzICAgICAxICAgICAxICAgICAgICAtNCAgICAgICAgMTIgICAgICA3MTkgICAgICAxNTAgICAgMTYgIDIuNTANCiM+ICMgLi4uIHdpdGggMy4zNjhlKzA1IG1vcmUgcm93cywgYW5kIDEgbW9yZSB2YXJpYWJsZXM6IGdhaW5fcGVyX2hvdXIgPGRibD4NCmBgYA0KDQorINPDIGB0cmFuc211dGUoKWAgvfa99rGjwfTQwtT2tcTB0A0KYGBge3J9DQp0cmFuc211dGUoZmxpZ2h0cywNCiAgZ2FpbiA9IGFycl9kZWxheSAtIGRlcF9kZWxheSwNCiAgaG91cnMgPSBhaXJfdGltZSAvIDYwLA0KICBnYWluX3Blcl9ob3VyID0gZ2FpbiAvIGhvdXJzDQopDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMzM2LDc3NiChwSAzDQojPiAgICBnYWluIGhvdXJzIGdhaW5fcGVyX2hvdXINCiM+ICAgPGRibD4gPGRibD4gICAgICAgICA8ZGJsPg0KIz4gMSAgICAgOSAgMy43OCAgICAgICAgICAyLjM4DQojPiAyICAgIDE2ICAzLjc4ICAgICAgICAgIDQuMjMNCiM+IDMgICAgMzEgIDIuNjcgICAgICAgICAxMS42Mg0KIz4gNCAgIC0xNyAgMy4wNSAgICAgICAgIC01LjU3DQojPiA1ICAgLTE5ICAxLjkzICAgICAgICAgLTkuODMNCiM+IDYgICAgMTYgIDIuNTAgICAgICAgICAgNi40MA0KIz4gIyAuLi4gd2l0aCAzLjM2OGUrMDUgbW9yZSByb3dzDQpgYGANCg0KIyMgNS4yIL/J0tTTw9PavMbL49DCseTBv7XEz/LBv7uv1MvL47f7DQorIEFyaXRobWV0aWMgb3BlcmF0b3JzOiBgK2AsIGAtYCwgYCpgLCBgL2AsIGBeYC4NCg0KKyBNb2R1bGFyIGFyaXRobWV0aWM6IGAlLyVgIChpbnRlZ2VyIGRpdmlzaW9uKSBhbmQgYCUlYCAocmVtYWluZGVyKS4NCmBgYHtyfQ0KdHJhbnNtdXRlKGZsaWdodHMsDQogIGRlcF90aW1lLA0KICBob3VyID0gZGVwX3RpbWUgJS8lIDEwMCwNCiAgbWludXRlID0gZGVwX3RpbWUgJSUgMTAwDQopDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMzM2LDc3NiChwSAzDQojPiAgIGRlcF90aW1lICBob3VyIG1pbnV0ZQ0KIz4gICAgICA8aW50PiA8ZGJsPiAgPGRibD4NCiM+IDEgICAgICA1MTcgICAgIDUgICAgIDE3DQojPiAyICAgICAgNTMzICAgICA1ICAgICAzMw0KIz4gMyAgICAgIDU0MiAgICAgNSAgICAgNDINCiM+IDQgICAgICA1NDQgICAgIDUgICAgIDQ0DQojPiA1ICAgICAgNTU0ICAgICA1ICAgICA1NA0KIz4gNiAgICAgIDU1NCAgICAgNSAgICAgNTQNCiM+ICMgLi4uIHdpdGggMy4zNjhlKzA1IG1vcmUgcm93cw0KYGBgDQoNCisgTG9nczogYGxvZygpYCwgYGxvZzIoKWAsIGBsb2cxMCgpYC4gDQoNCisgT2Zmc2V0czogYGxlYWQoKWAgYW5kIGBsYWcoKWAgYWxsb3cgeW91IHRvIHJlZmVyIHRvIGxlYWRpbmcgb3IgbGFnZ2luZyB2YWx1ZXMuDQpgYGB7cn0NCih4IDwtIDE6MTApDQpgYGANCmBgYHtyfQ0KbGFnKHgpDQpgYGANCmBgYHtyfQ0KbGVhZCh4KQ0KYGBgDQpgYGB7cn0NCiMgY29tcHV0ZSBydW5uaW5nIGRpZmZlcmVuY2VzDQp4IC0gbGFnKHgpDQpgYGANCmBgYHtyfQ0KIyBmaW5kIHdoZW4gdmFsdWVzIGNoYW5nZQ0KeCAhPSBsYWcoeCkNCmBgYA0KDQorIEN1bXVsYXRpdmUgYW5kIHJvbGxpbmcgYWdncmVnYXRlczogYGN1bXN1bSgpYCwgYGN1bXByb2QoKWAsIGBjdW1taW4oKWAsIGBjdW1tYXgoKWAsIGBjdW1tZWFuKClgLiAgDQpJZiB5b3UgbmVlZCByb2xsaW5nIGFnZ3JlZ2F0ZXMgKGkuZS4gYSBzdW0gY29tcHV0ZWQgb3ZlciBhIHJvbGxpbmcgd2luZG93KSwgdHJ5IHRoZSBgUmNwcFJvbGxgIHBhY2thZ2UuDQpgYGB7cn0NCngNCmBgYA0KYGBge3J9DQpjdW1zdW0oeCkNCmBgYA0KYGBge3J9DQpjdW1tZWFuKHgpDQpgYGANCg0KKyBMb2dpY2FsIGNvbXBhcmlzb25zLCBgPGAsIGA8PWAsIGA+YCwgYD49YCwgYCE9YC4NCg0KKyBSYW5raW5nOiBgbWluX3JhbmsoKWAsIGByb3dfbnVtYmVyKClgLCBgZGVuc2VfcmFuaygpYCwgYHBlcmNlbnRfcmFuaygpYCwgYGN1bWVfZGlzdCgpYCwgYG50aWxlKClgLg0KYGBge3J9DQooeSA8LSBjKDEsIDIsIDIsIE5BLCAzLCA0KSkNCmBgYA0KYGBge3J9DQptaW5fcmFuayh5KQ0KYGBgDQpgYGB7cn0NCm1pbl9yYW5rKGRlc2MoeSkpDQpgYGANCmBgYHtyfQ0Kcm93X251bWJlcih5KQ0KYGBgDQpgYGB7cn0NCmRlbnNlX3JhbmsoeSkNCmBgYA0KYGBge3J9DQpwZXJjZW50X3JhbmsoeSkNCmBgYA0KYGBge3J9DQpjdW1lX2Rpc3QoeSkNCmBgYA0KDQojIDYg08MgYHN1bW1hcmlzZSgpYCC8xsvjt9bX6c2zvMbBvw0KIyMgNi4xIGBncm91cF9ieSgpYCC6zSBgc3VtbWFyaXNlKClgIMGqus/KudPDo6y8xsvjt9bX6c2zvMbBvw0KYGBge3J9DQpzdW1tYXJpc2UoZmxpZ2h0cywgZGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSkNCmBgYA0KYGBgDQojPiAjIEEgdGliYmxlOiAxIKHBIDENCiM+ICAgZGVsYXkNCiM+ICAgPGRibD4NCiM+IDEgIDEyLjYNCmBgYA0KDQpgYGB7cn0NCmJ5X2RheSA8LSBncm91cF9ieShmbGlnaHRzLCB5ZWFyLCBtb250aCwgZGF5KQ0Kc3VtbWFyaXNlKGJ5X2RheSwgZGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSkNCmBgYA0KYGBgDQojPiBTb3VyY2U6IGxvY2FsIGRhdGEgZnJhbWUgWzM2NSB4IDRdDQojPiBHcm91cHM6IHllYXIsIG1vbnRoIFs/XQ0KIz4gDQojPiAgICB5ZWFyIG1vbnRoICAgZGF5IGRlbGF5DQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+IDxkYmw+DQojPiAxICAyMDEzICAgICAxICAgICAxIDExLjU1DQojPiAyICAyMDEzICAgICAxICAgICAyIDEzLjg2DQojPiAzICAyMDEzICAgICAxICAgICAzIDEwLjk5DQojPiA0ICAyMDEzICAgICAxICAgICA0ICA4Ljk1DQojPiA1ICAyMDEzICAgICAxICAgICA1ICA1LjczDQojPiA2ICAyMDEzICAgICAxICAgICA2ICA3LjE1DQojPiAjIC4uLiB3aXRoIDM1OSBtb3JlIHJvd3MNCmBgYA0KDQojIyA2LjIgudy1wLLZ1/e3+yBgJT4lYA0KKyDMvcv3ttTT2rK7zay12LXjo6zGvb75t8nQ0L7gwOvT68a9vvnR087zyrG85NauvOS1xLnYz7Who7/J0tS3os/Wo6zGvb75t8nQ0L7gwOvOqjc1MNOiwO/KsaOsxr2++dHTzvPKsbzktO+1vbfl1rWjrL/JxNzKx9PJ09q4/LOktcS3ydDQvuDA66OszqrD1rK50dPO88zhuanBy7/JxNyhow0KYGBge3J9DQpieV9kZXN0IDwtIGdyb3VwX2J5KGZsaWdodHMsIGRlc3QpDQoNCmRlbGF5IDwtIHN1bW1hcmlzZShieV9kZXN0LA0KICBjb3VudCA9IG4oKSwNCiAgZGlzdCA9IG1lYW4oZGlzdGFuY2UsIG5hLnJtID0gVFJVRSksDQogIGRlbGF5ID0gbWVhbihhcnJfZGVsYXksIG5hLnJtID0gVFJVRSkNCikNCg0KKGRlbGF5IDwtIGZpbHRlcihkZWxheSwgY291bnQgPiAyMCwgZGVzdCAhPSAiSE5MIikpDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogOTYgocEgNA0KIz4gICAgIGRlc3QgY291bnQgICAgICBkaXN0ICAgICBkZWxheQ0KIz4gICAgPGNocj4gPGludD4gICAgIDxkYmw+ICAgICA8ZGJsPg0KIz4gMSAgICBBQlEgICAyNTQgMTgyNi4wMDAwICA0LjM4MTg5MA0KIz4gMiAgICBBQ0sgICAyNjUgIDE5OS4wMDAwICA0Ljg1MjI3Mw0KIz4gMyAgICBBTEIgICA0MzkgIDE0My4wMDAwIDE0LjM5NzEyOQ0KIz4gNCAgICBBVEwgMTcyMTUgIDc1Ny4xMDgyIDExLjMwMDExMw0KIz4gNSAgICBBVVMgIDI0MzkgMTUxNC4yNTMwICA2LjAxOTkwOQ0KIz4gNiAgICBBVkwgICAyNzUgIDU4My41ODE4ICA4LjAwMzgzMQ0KIz4gNyAgICBCREwgICA0NDMgIDExNi4wMDAwICA3LjA0ODU0NA0KIz4gOCAgICBCR1IgICAzNzUgIDM3OC4wMDAwICA4LjAyNzkzMw0KIz4gOSAgICBCSE0gICAyOTcgIDg2NS45OTY2IDE2Ljg3NzMyMw0KIz4gMTAgICBCTkEgIDYzMzMgIDc1OC4yMTM1IDExLjgxMjQ1OQ0KIz4gIyAuLi4gd2l0aCA4NiBtb3JlIHJvd3MNCmBgYA0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGRlbGF5LCBtYXBwaW5nID0gYWVzKHggPSBkaXN0LCB5ID0gZGVsYXkpKSArDQogIGdlb21fcG9pbnQoYWVzKHNpemUgPSBjb3VudCksIGFscGhhID0gMS8zKSArDQogIGdlb21fc21vb3RoKHNlID0gRkFMU0UpDQpgYGANCg0KKyDK/b7d1KS0psDtyea8sDO49rK91uijug0KICAgICsg0sC+3cS/tcS12LfW1+kNCiAgICArILzGy+O31tfpuvO1xMa9vvm3ydDQvuDA66Gixr2++dHTzvPKsbzkus26vbDgyv0NCiAgICArILn9wsu19M/Ezf7SxLv6s6GjqMa9vvm3ydDQvuDA68rHxuTL+7v6s6G1xDKxttLUyc+jqbrNur2w4Mr9uf3J2bXExL+1xLXYDQoNCg0KKyDKudPDudy1wLLZ1/e3+yBgJT4lYCDN6rPJ0tTJzzO49rK91ugNCmBgYHtyfQ0KZGVsYXlzIDwtIGZsaWdodHMgJT4lIA0KICBncm91cF9ieShkZXN0KSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBjb3VudCA9IG4oKSwNCiAgICBkaXN0ID0gbWVhbihkaXN0YW5jZSwgbmEucm0gPSBUUlVFKSwNCiAgICBkZWxheSA9IG1lYW4oYXJyX2RlbGF5LCBuYS5ybSA9IFRSVUUpDQogICkgJT4lIA0KICBmaWx0ZXIoY291bnQgPiAyMCwgZGVzdCAhPSAiSE5MIikNCmBgYA0KDQojIyA2LjMgyLHKp9a1DQorIMixyqfWtbSryOu+27rPuq/K/aOs0rK74be1u9jIscqn1rUNCmBgYHtyfQ0KZmxpZ2h0cyAlPiUgDQogIGdyb3VwX2J5KHllYXIsIG1vbnRoLCBkYXkpICU+JSANCiAgc3VtbWFyaXNlKG1lYW4gPSBtZWFuKGRlcF9kZWxheSkpDQpgYGANCmBgYA0KIz4gU291cmNlOiBsb2NhbCBkYXRhIGZyYW1lIFszNjUgeCA0XQ0KIz4gR3JvdXBzOiB5ZWFyLCBtb250aCBbP10NCiM+IA0KIz4gICAgeWVhciBtb250aCAgIGRheSAgbWVhbg0KIz4gICA8aW50PiA8aW50PiA8aW50PiA8ZGJsPg0KIz4gMSAgMjAxMyAgICAgMSAgICAgMSAgICBOQQ0KIz4gMiAgMjAxMyAgICAgMSAgICAgMiAgICBOQQ0KIz4gMyAgMjAxMyAgICAgMSAgICAgMyAgICBOQQ0KIz4gNCAgMjAxMyAgICAgMSAgICAgNCAgICBOQQ0KIz4gNSAgMjAxMyAgICAgMSAgICAgNSAgICBOQQ0KIz4gNiAgMjAxMyAgICAgMSAgICAgNiAgICBOQQ0KIz4gIyAuLi4gd2l0aCAzNTkgbW9yZSByb3dzDQpgYGANCisgyrnTwyBgbmEucm1gILLOyv0NCmBgYHtyfQ0KZmxpZ2h0cyAlPiUgDQogIGdyb3VwX2J5KHllYXIsIG1vbnRoLCBkYXkpICU+JSANCiAgc3VtbWFyaXNlKG1lYW4gPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSkNCmBgYA0KYGBgDQojPiBTb3VyY2U6IGxvY2FsIGRhdGEgZnJhbWUgWzM2NSB4IDRdDQojPiBHcm91cHM6IHllYXIsIG1vbnRoIFs/XQ0KIz4gDQojPiAgICB5ZWFyIG1vbnRoICAgZGF5ICBtZWFuDQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+IDxkYmw+DQojPiAxICAyMDEzICAgICAxICAgICAxIDExLjU1DQojPiAyICAyMDEzICAgICAxICAgICAyIDEzLjg2DQojPiAzICAyMDEzICAgICAxICAgICAzIDEwLjk5DQojPiA0ICAyMDEzICAgICAxICAgICA0ICA4Ljk1DQojPiA1ICAyMDEzICAgICAxICAgICA1ICA1LjczDQojPiA2ICAyMDEzICAgICAxICAgICA2ICA3LjE1DQojPiAjIC4uLiB3aXRoIDM1OSBtb3JlIHJvd3MNCmBgYA0KKyDPyNDQzN6z/SBgTkFgINa1DQpgYGB7cn0NCm5vdF9jYW5jZWxsZWQgPC0gZmxpZ2h0cyAlPiUgDQogIGZpbHRlcighaXMubmEoZGVwX2RlbGF5KSwgIWlzLm5hKGFycl9kZWxheSkpDQoNCm5vdF9jYW5jZWxsZWQgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBtb250aCwgZGF5KSAlPiUgDQogIHN1bW1hcmlzZShtZWFuID0gbWVhbihkZXBfZGVsYXkpKQ0KYGBgDQpgYGANCiM+IFNvdXJjZTogbG9jYWwgZGF0YSBmcmFtZSBbMzY1IHggNF0NCiM+IEdyb3VwczogeWVhciwgbW9udGggWz9dDQojPiANCiM+ICAgIHllYXIgbW9udGggICBkYXkgIG1lYW4NCiM+ICAgPGludD4gPGludD4gPGludD4gPGRibD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgMTEuNDQNCiM+IDIgIDIwMTMgICAgIDEgICAgIDIgMTMuNjgNCiM+IDMgIDIwMTMgICAgIDEgICAgIDMgMTAuOTENCiM+IDQgIDIwMTMgICAgIDEgICAgIDQgIDguOTcNCiM+IDUgIDIwMTMgICAgIDEgICAgIDUgIDUuNzMNCiM+IDYgIDIwMTMgICAgIDEgICAgIDYgIDcuMTUNCiM+ICMgLi4uIHdpdGggMzU5IG1vcmUgcm93cw0KYGBgDQojIyA2LjQgvMbK/aOoYGNvdW50YKOpDQrU2rzGy+O31tfpzbO8xsG/tcTKsbryo6zQ6NKqv7zCx9fpxNrR+bG+tcS49sr9o6hgbigpYKOpoaK3x8ixyqfWtbXEuPbK/aOoYHN1bSghaXMubmEoeCkpYKOp0tS8sLfW1+m1xLj2yv0gIA0KDQorINPDIGB0YWlsbnVtYCDH+LfWt8m7+qOs08O6y8PctsjNvLfWzva3ybv6tcTGvb750dPO88qxvOS31rK8x+m/9g0KYGBge3J9DQpkZWxheXMgPC0gbm90X2NhbmNlbGxlZCAlPiUgDQogIGdyb3VwX2J5KHRhaWxudW0pICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIGRlbGF5ID0gbWVhbihhcnJfZGVsYXkpDQogICkNCg0KZGVsYXlzDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogNCwwMzcgocEgMg0KIz4gICAgdGFpbG51bSAgICAgIGRlbGF5DQojPiAgICAgIDxjaHI+ICAgICAgPGRibD4NCiM+IDEgICBEOTQyRE4gMzEuNTAwMDAwMA0KIz4gMiAgIE4wRUdNUSAgOS45ODI5NTQ1DQojPiAzICAgTjEwMTU2IDEyLjcxNzI0MTQNCiM+IDQgICBOMTAyVVcgIDIuOTM3NTAwMA0KIz4gNSAgIE4xMDNVUyAtNi45MzQ3ODI2DQojPiA2ICAgTjEwNFVXICAxLjgwNDM0NzgNCiM+IDcgICBOMTA1NzUgMjAuNjkxNDQ5OA0KIz4gOCAgIE4xMDVVVyAtMC4yNjY2NjY3DQojPiA5ICAgTjEwN1VTIC01LjczMTcwNzMNCiM+IDEwICBOMTA4VVcgLTEuMjUwMDAwMA0KIz4gIyAuLi4gd2l0aCA0LDAyNyBtb3JlIHJvd3MNCmBgYA0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGRlbGF5cywgbWFwcGluZyA9IGFlcyh4ID0gZGVsYXkpKSArIA0KICBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gMTApDQpgYGANCg0KKyDTwyBgbigpYCC8xsvj1+nE2tH5sb649sr9o6y008mitePNvL/J0tS/tLP2o6y3ydDQtM7K/cnZtcS3ybv6o6zGvb750dPO88qxvOS1xLHk0uyzzLbIuPy08w0KYGBge3J9DQpkZWxheXMgPC0gbm90X2NhbmNlbGxlZCAlPiUgDQogIGdyb3VwX2J5KHRhaWxudW0pICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIGRlbGF5ID0gbWVhbihhcnJfZGVsYXksIG5hLnJtID0gVFJVRSksDQogICAgbiA9IG4oKQ0KICApDQoNCmRlbGF5cw0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDQsMDM3IKHBIDMNCiM+ICAgIHRhaWxudW0gICAgICBkZWxheSAgICAgbg0KIz4gICAgICA8Y2hyPiAgICAgIDxkYmw+IDxpbnQ+DQojPiAxICAgRDk0MkROIDMxLjUwMDAwMDAgICAgIDQNCiM+IDIgICBOMEVHTVEgIDkuOTgyOTU0NSAgIDM1Mg0KIz4gMyAgIE4xMDE1NiAxMi43MTcyNDE0ICAgMTQ1DQojPiA0ICAgTjEwMlVXICAyLjkzNzUwMDAgICAgNDgNCiM+IDUgICBOMTAzVVMgLTYuOTM0NzgyNiAgICA0Ng0KIz4gNiAgIE4xMDRVVyAgMS44MDQzNDc4ICAgIDQ2DQojPiA3ICAgTjEwNTc1IDIwLjY5MTQ0OTggICAyNjkNCiM+IDggICBOMTA1VVcgLTAuMjY2NjY2NyAgICA0NQ0KIz4gOSAgIE4xMDdVUyAtNS43MzE3MDczICAgIDQxDQojPiAxMCAgTjEwOFVXIC0xLjI1MDAwMDAgICAgNjANCiM+ICMgLi4uIHdpdGggNCwwMjcgbW9yZSByb3dzDQpgYGANCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBkZWxheXMsIG1hcHBpbmcgPSBhZXMoeCA9IG4sIHkgPSBkZWxheSkpICsgDQogIGdlb21fcG9pbnQoYWxwaGEgPSAxLzEwKQ0KYGBgDQoNCisgwPvTwyBgZmlsdGVyKClgIMm40aGz9rfJ0NC0zsr9tPPT2jI1tcS3ybv6o6y31s72y/zDx7XE0dPO88fpv/YNCmBgYHtyfQ0KZGVsYXlzICU+JSANCiAgZmlsdGVyKG4gPiAyNSkgJT4lIA0KICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gbiwgeSA9IGRlbGF5KSkgKyANCiAgICBnZW9tX3BvaW50KGFscGhhID0gMS8xMCkNCmBgYA0KDQorIGBiYWAgtPqx7bv3tPKzybmmwsqjrCBgYWJgILT6se2797TytM7K/aOsu/e08rPJuabCytPru/e08sr91f3P4LnYo6y/ycTcysfS8s6qx/K208fjz/LT2sjDs8m5psLKuN+1xMfy1LHTtdPQuPy24LP2s6G7+rvhDQpgYGB7cn0NCiMgQ29udmVydCB0byBhIHRpYmJsZSBzbyBpdCBwcmludHMgbmljZWx5DQpiYXR0aW5nIDwtIGFzX3RpYmJsZShMYWhtYW46OkJhdHRpbmcpDQoNCmJhdHRlcnMgPC0gYmF0dGluZyAlPiUgDQogIGdyb3VwX2J5KHBsYXllcklEKSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBiYSA9IHN1bShILCBuYS5ybSA9IFRSVUUpIC8gc3VtKEFCLCBuYS5ybSA9IFRSVUUpLA0KICAgIGFiID0gc3VtKEFCLCBuYS5ybSA9IFRSVUUpDQogICkNCg0KYmF0dGVycyAlPiUgDQogIGZpbHRlcihhYiA+IDEwMCkgJT4lIA0KICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gYWIsIHkgPSBiYSkpICsNCiAgICBnZW9tX3BvaW50KCkgKyANCiAgICBnZW9tX3Ntb290aChzZSA9IEZBTFNFKQ0KYGBgDQoNCisg0sC+3SBgYmFgIL340NC9tdDyxcXB0KOsv8nS1L+0s/ajrLv3tPKzybmmwsrX7rjftcTH8tSxo6y797TytM7K/da709DSu7TOo6y0v7TiysfTydPa1MvG+Lb4t8e8vMr1DQpgYGB7cn0NCmJhdHRlcnMgJT4lIA0KICBhcnJhbmdlKGRlc2MoYmEpKQ0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDE4LDY1OSChwSAzDQojPiAgICBwbGF5ZXJJRCAgICBiYSAgICBhYg0KIz4gICAgICAgPGNocj4gPGRibD4gPGludD4NCiM+IDEgYWJyYW1nZTAxICAgICAxICAgICAxDQojPiAyIGJhbmlzamUwMSAgICAgMSAgICAgMQ0KIz4gMyBiYXJ0b2NsMDEgICAgIDEgICAgIDENCiM+IDQgIGJhc3NkbzAxICAgICAxICAgICAxDQojPiA1IGJpcmFzc3QwMSAgICAgMSAgICAgMg0KIz4gNiBicnVuZWp1MDEgICAgIDEgICAgIDENCiM+ICMgLi4uIHdpdGggMS44NjVlKzA0IG1vcmUgcm93cw0KYGBgDQoNCiMjIDYuNSC+27rPzbO8xrqvyv0NCisgTWVhc3VyZXMgb2YgbG9jYXRpb246IGBtZWFuKHgpYCwgYG1lZGlhbih4KWAuDQpgYGB7cn0NCm5vdF9jYW5jZWxsZWQgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBtb250aCwgZGF5KSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBhdmdfZGVsYXkxID0gbWVhbihhcnJfZGVsYXkpLA0KICAgIGF2Z19kZWxheTIgPSBtZWFuKGFycl9kZWxheVthcnJfZGVsYXkgPiAwXSkgIyB0aGUgYXZlcmFnZSBwb3NpdGl2ZSBkZWxheQ0KICApDQpgYGANCmBgYA0KIz4gU291cmNlOiBsb2NhbCBkYXRhIGZyYW1lIFszNjUgeCA1XQ0KIz4gR3JvdXBzOiB5ZWFyLCBtb250aCBbP10NCiM+IA0KIz4gICAgeWVhciBtb250aCAgIGRheSBhdmdfZGVsYXkxIGF2Z19kZWxheTINCiM+ICAgPGludD4gPGludD4gPGludD4gICAgICA8ZGJsPiAgICAgIDxkYmw+DQojPiAxICAyMDEzICAgICAxICAgICAxICAgICAgMTIuNjUgICAgICAgMzIuNQ0KIz4gMiAgMjAxMyAgICAgMSAgICAgMiAgICAgIDEyLjY5ICAgICAgIDMyLjANCiM+IDMgIDIwMTMgICAgIDEgICAgIDMgICAgICAgNS43MyAgICAgICAyNy43DQojPiA0ICAyMDEzICAgICAxICAgICA0ICAgICAgLTEuOTMgICAgICAgMjguMw0KIz4gNSAgMjAxMyAgICAgMSAgICAgNSAgICAgIC0xLjUzICAgICAgIDIyLjYNCiM+IDYgIDIwMTMgICAgIDEgICAgIDYgICAgICAgNC4yNCAgICAgICAyNC40DQojPiAjIC4uLiB3aXRoIDM1OSBtb3JlIHJvd3MNCmBgYA0KDQorIE1lYXN1cmVzIG9mIHNwcmVhZDogYHNkKHgpYCwgYElRUih4KWAsIGBtYWQoeClgLg0KYGBge3J9DQojIFdoeSBpcyBkaXN0YW5jZSB0byBzb21lIGRlc3RpbmF0aW9ucyBtb3JlIHZhcmlhYmxlIHRoYW4gdG8gb3RoZXJzPw0Kbm90X2NhbmNlbGxlZCAlPiUgDQogIGdyb3VwX2J5KGRlc3QpICU+JSANCiAgc3VtbWFyaXNlKGRpc3RhbmNlX3NkID0gc2QoZGlzdGFuY2UpKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhkaXN0YW5jZV9zZCkpDQpgYGANCmBgYA0KIz4gIyBBIHRpYmJsZTogMTA0IKHBIDINCiM+ICAgIGRlc3QgZGlzdGFuY2Vfc2QNCiM+ICAgPGNocj4gICAgICAgPGRibD4NCiM+IDEgICBFR0UgICAgICAgMTAuNTQNCiM+IDIgICBTQU4gICAgICAgMTAuMzUNCiM+IDMgICBTRk8gICAgICAgMTAuMjINCiM+IDQgICBITkwgICAgICAgMTAuMDANCiM+IDUgICBTRUEgICAgICAgIDkuOTgNCiM+IDYgICBMQVMgICAgICAgIDkuOTENCiM+ICMgLi4uIHdpdGggOTggbW9yZSByb3dzDQpgYGANCisgTWVhc3VyZXMgb2YgcmFuazogYG1pbih4KWAsIGBxdWFudGlsZSh4LCAwLjI1KWAsIGBtYXgoeClgLiANCmBgYHtyfQ0KIyBXaGVuIGRvIHRoZSBmaXJzdCBhbmQgbGFzdCBmbGlnaHRzIGxlYXZlIGVhY2ggZGF5Pw0Kbm90X2NhbmNlbGxlZCAlPiUgDQogIGdyb3VwX2J5KHllYXIsIG1vbnRoLCBkYXkpICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIGZpcnN0ID0gbWluKGRlcF90aW1lKSwNCiAgICBsYXN0ID0gbWF4KGRlcF90aW1lKQ0KICApDQpgYGANCmBgYA0KIz4gU291cmNlOiBsb2NhbCBkYXRhIGZyYW1lIFszNjUgeCA1XQ0KIz4gR3JvdXBzOiB5ZWFyLCBtb250aCBbP10NCiM+IA0KIz4gICAgeWVhciBtb250aCAgIGRheSBmaXJzdCAgbGFzdA0KIz4gICA8aW50PiA8aW50PiA8aW50PiA8aW50PiA8aW50Pg0KIz4gMSAgMjAxMyAgICAgMSAgICAgMSAgIDUxNyAgMjM1Ng0KIz4gMiAgMjAxMyAgICAgMSAgICAgMiAgICA0MiAgMjM1NA0KIz4gMyAgMjAxMyAgICAgMSAgICAgMyAgICAzMiAgMjM0OQ0KIz4gNCAgMjAxMyAgICAgMSAgICAgNCAgICAyNSAgMjM1OA0KIz4gNSAgMjAxMyAgICAgMSAgICAgNSAgICAxNCAgMjM1Nw0KIz4gNiAgMjAxMyAgICAgMSAgICAgNiAgICAxNiAgMjM1NQ0KIz4gIyAuLi4gd2l0aCAzNTkgbW9yZSByb3dzDQpgYGANCg0KKyBNZWFzdXJlcyBvZiBwb3NpdGlvbjogYGZpcnN0KHgpYCwgYG50aCh4LCAyKWAsIGBsYXN0KHgpYC4gDQpgYGB7cn0NCm5vdF9jYW5jZWxsZWQgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBtb250aCwgZGF5KSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBmaXJzdF9kZXAgPSBmaXJzdChkZXBfdGltZSksIA0KICAgIGxhc3RfZGVwID0gbGFzdChkZXBfdGltZSkNCiAgKQ0KYGBgDQpgYGANCiM+IFNvdXJjZTogbG9jYWwgZGF0YSBmcmFtZSBbMzY1IHggNV0NCiM+IEdyb3VwczogeWVhciwgbW9udGggWz9dDQojPiANCiM+ICAgIHllYXIgbW9udGggICBkYXkgZmlyc3RfZGVwIGxhc3RfZGVwDQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+ICAgICA8aW50PiAgICA8aW50Pg0KIz4gMSAgMjAxMyAgICAgMSAgICAgMSAgICAgICA1MTcgICAgIDIzNTYNCiM+IDIgIDIwMTMgICAgIDEgICAgIDIgICAgICAgIDQyICAgICAyMzU0DQojPiAzICAyMDEzICAgICAxICAgICAzICAgICAgICAzMiAgICAgMjM0OQ0KIz4gNCAgMjAxMyAgICAgMSAgICAgNCAgICAgICAgMjUgICAgIDIzNTgNCiM+IDUgIDIwMTMgICAgIDEgICAgIDUgICAgICAgIDE0ICAgICAyMzU3DQojPiA2ICAyMDEzICAgICAxICAgICA2ICAgICAgICAxNiAgICAgMjM1NQ0KIz4gIyAuLi4gd2l0aCAzNTkgbW9yZSByb3dzDQpgYGANCg0KzazR+bXE0Ke5+6Osv8nS1M2ouf3S1M/Ct723qMq1z9ajrLKix9K74bGjwfTL+dPQtcSx5MG/o6zXotLiIGBtdXRhdGUoKWAsIGBtaW5fcmFua2AsIGBmaWx0ZXIoKWAg1NrV4sDvtcTX99PDDQpgYGB7cn0NCm5vdF9jYW5jZWxsZWQgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBtb250aCwgZGF5KSAlPiUgDQogIG11dGF0ZShyID0gbWluX3JhbmsoZGVzYyhkZXBfdGltZSkpKSAlPiUgDQogIGZpbHRlcihyICVpbiUgcmFuZ2UocikpDQpgYGANCmBgYA0KIz4gU291cmNlOiBsb2NhbCBkYXRhIGZyYW1lIFs3NzAgeCAyMF0NCiM+IEdyb3VwczogeWVhciwgbW9udGgsIGRheSBbMzY1XQ0KIz4gDQojPiAgICB5ZWFyIG1vbnRoICAgZGF5IGRlcF90aW1lIHNjaGVkX2RlcF90aW1lIGRlcF9kZWxheSBhcnJfdGltZQ0KIz4gICA8aW50PiA8aW50PiA8aW50PiAgICA8aW50PiAgICAgICAgICA8aW50PiAgICAgPGRibD4gICAgPGludD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICAgICA1MTcgICAgICAgICAgICA1MTUgICAgICAgICAyICAgICAgODMwDQojPiAyICAyMDEzICAgICAxICAgICAxICAgICAyMzU2ICAgICAgICAgICAyMzU5ICAgICAgICAtMyAgICAgIDQyNQ0KIz4gMyAgMjAxMyAgICAgMSAgICAgMiAgICAgICA0MiAgICAgICAgICAgMjM1OSAgICAgICAgNDMgICAgICA1MTgNCiM+IDQgIDIwMTMgICAgIDEgICAgIDIgICAgIDIzNTQgICAgICAgICAgIDIzNTkgICAgICAgIC01ICAgICAgNDEzDQojPiA1ICAyMDEzICAgICAxICAgICAzICAgICAgIDMyICAgICAgICAgICAyMzU5ICAgICAgICAzMyAgICAgIDUwNA0KIz4gNiAgMjAxMyAgICAgMSAgICAgMyAgICAgMjM0OSAgICAgICAgICAgMjM1OSAgICAgICAtMTAgICAgICA0MzQNCiM+ICMgLi4uIHdpdGggNzY0IG1vcmUgcm93cywgYW5kIDEzIG1vcmUgdmFyaWFibGVzOiBzY2hlZF9hcnJfdGltZSA8aW50PiwNCiM+ICMgICBhcnJfZGVsYXkgPGRibD4sIGNhcnJpZXIgPGNocj4sIGZsaWdodCA8aW50PiwgdGFpbG51bSA8Y2hyPiwNCiM+ICMgICBvcmlnaW4gPGNocj4sIGRlc3QgPGNocj4sIGFpcl90aW1lIDxkYmw+LCBkaXN0YW5jZSA8ZGJsPiwgaG91ciA8ZGJsPiwNCiM+ICMgICBtaW51dGUgPGRibD4sIHRpbWVfaG91ciA8ZHR0bT4sIHIgPGludD4NCmBgYA0KDQorIENvdW50czogYGNvdW50KClgLCBgbigpYCwgYHN1bSghaXMubmEoeCkpYCwgYG5fZGlzdGluY3QoeClgLg0KYGBge3J9DQojIFdoaWNoIGRlc3RpbmF0aW9ucyBoYXZlIHRoZSBtb3N0IGNhcnJpZXJzPw0Kbm90X2NhbmNlbGxlZCAlPiUgDQogIGdyb3VwX2J5KGRlc3QpICU+JSANCiAgc3VtbWFyaXNlKGNhcnJpZXJzID0gbl9kaXN0aW5jdChjYXJyaWVyKSkgJT4lIA0KICBhcnJhbmdlKGRlc2MoY2FycmllcnMpKQ0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDEwNCChwSAyDQojPiAgICBkZXN0IGNhcnJpZXJzDQojPiAgIDxjaHI+ICAgIDxpbnQ+DQojPiAxICAgQVRMICAgICAgICA3DQojPiAyICAgQk9TICAgICAgICA3DQojPiAzICAgQ0xUICAgICAgICA3DQojPiA0ICAgT1JEICAgICAgICA3DQojPiA1ICAgVFBBICAgICAgICA3DQojPiA2ICAgQVVTICAgICAgICA2DQojPiAjIC4uLiB3aXRoIDk4IG1vcmUgcm93cw0KYGBgDQoNCse/tPO1xCBgY291bnQoKWAguq/K/aOstMu0przGy+PDv7j2u/qzodf3zqrEv7XEtdi1xLq9sODK/Q0KYGBge3J9DQpub3RfY2FuY2VsbGVkICU+JSANCiAgY291bnQoZGVzdCkNCmBgYA0KYGBgDQojPiAjIEEgdGliYmxlOiAxMDQgocEgMg0KIz4gICAgZGVzdCAgICAgbg0KIz4gICA8Y2hyPiA8aW50Pg0KIz4gMSAgIEFCUSAgIDI1NA0KIz4gMiAgIEFDSyAgIDI2NA0KIz4gMyAgIEFMQiAgIDQxOA0KIz4gNCAgIEFOQyAgICAgOA0KIz4gNSAgIEFUTCAxNjgzNw0KIz4gNiAgIEFVUyAgMjQxMQ0KIz4gIyAuLi4gd2l0aCA5OCBtb3JlIHJvd3MNCmBgYA0KDQpgY291bnQoKWAgv8nS1NPD09q808iovMbK/aOstMu0przGy+PDv7zct8m7+rXE19y3ydDQwO+zzA0KYGBge3J9DQpub3RfY2FuY2VsbGVkICU+JSANCiAgY291bnQodGFpbG51bSwgd3QgPSBkaXN0YW5jZSkNCmBgYA0KYGBgDQojPiAjIEEgdGliYmxlOiA0LDAzNyChwSAyDQojPiAgIHRhaWxudW0gICAgICBuDQojPiAgICAgPGNocj4gIDxkYmw+DQojPiAxICBEOTQyRE4gICAzNDE4DQojPiAyICBOMEVHTVEgMjM5MTQzDQojPiAzICBOMTAxNTYgMTA5NjY0DQojPiA0ICBOMTAyVVcgIDI1NzIyDQojPiA1ICBOMTAzVVMgIDI0NjE5DQojPiA2ICBOMTA0VVcgIDI0NjE2DQojPiAjIC4uLiB3aXRoIDQsMDMxIG1vcmUgcm93cw0KYGBgDQoNCisgQ291bnRzIGFuZCBwcm9wb3J0aW9ucyBvZiBsb2dpY2FsIHZhbHVlczogYHN1bSh4ID4gMTApYCwgYG1lYW4oeSA9PSAwKWAuIGBzdW0oeClgIGdpdmVzIHRoZSBudW1iZXIgb2YgYFRSVUVzYCBpbiBgeGAsIGFuZCBgbWVhbih4KWAgZ2l2ZXMgdGhlIHByb3BvcnRpb24uDQpgYGB7cn0NCiMgSG93IG1hbnkgZmxpZ2h0cyBsZWZ0IGJlZm9yZSA1YW0/ICh0aGVzZSB1c3VhbGx5IGluZGljYXRlIGRlbGF5ZWQNCiMgZmxpZ2h0cyBmcm9tIHRoZSBwcmV2aW91cyBkYXkpDQpub3RfY2FuY2VsbGVkICU+JSANCiAgZ3JvdXBfYnkoeWVhciwgbW9udGgsIGRheSkgJT4lIA0KICBzdW1tYXJpc2Uobl9lYXJseSA9IHN1bShkZXBfdGltZSA8IDUwMCkpDQpgYGANCmBgYA0KIz4gU291cmNlOiBsb2NhbCBkYXRhIGZyYW1lIFszNjUgeCA0XQ0KIz4gR3JvdXBzOiB5ZWFyLCBtb250aCBbP10NCiM+IA0KIz4gICAgeWVhciBtb250aCAgIGRheSBuX2Vhcmx5DQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+ICAgPGludD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICAgICAgMA0KIz4gMiAgMjAxMyAgICAgMSAgICAgMiAgICAgICAzDQojPiAzICAyMDEzICAgICAxICAgICAzICAgICAgIDQNCiM+IDQgIDIwMTMgICAgIDEgICAgIDQgICAgICAgMw0KIz4gNSAgMjAxMyAgICAgMSAgICAgNSAgICAgICAzDQojPiA2ICAyMDEzICAgICAxICAgICA2ICAgICAgIDINCiM+ICMgLi4uIHdpdGggMzU5IG1vcmUgcm93cw0KYGBgDQoNCmBgYHtyfQ0KIyBXaGF0IHByb3BvcnRpb24gb2YgZmxpZ2h0cyBhcmUgZGVsYXllZCBieSBtb3JlIHRoYW4gYW4gaG91cj8NCm5vdF9jYW5jZWxsZWQgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBtb250aCwgZGF5KSAlPiUgDQogIHN1bW1hcmlzZShob3VyX3BlcmMgPSBtZWFuKGFycl9kZWxheSA+IDYwKSkNCmBgYA0KYGBgDQojPiBTb3VyY2U6IGxvY2FsIGRhdGEgZnJhbWUgWzM2NSB4IDRdDQojPiBHcm91cHM6IHllYXIsIG1vbnRoIFs/XQ0KIz4gDQojPiAgICB5ZWFyIG1vbnRoICAgZGF5IGhvdXJfcGVyYw0KIz4gICA8aW50PiA8aW50PiA8aW50PiAgICAgPGRibD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICAgMC4wNzIyDQojPiAyICAyMDEzICAgICAxICAgICAyICAgIDAuMDg1MQ0KIz4gMyAgMjAxMyAgICAgMSAgICAgMyAgICAwLjA1NjcNCiM+IDQgIDIwMTMgICAgIDEgICAgIDQgICAgMC4wMzk2DQojPiA1ICAyMDEzICAgICAxICAgICA1ICAgIDAuMDM0OQ0KIz4gNiAgMjAxMyAgICAgMSAgICAgNiAgICAwLjA0NzANCiM+ICMgLi4uIHdpdGggMzU5IG1vcmUgcm93cw0KYGBgDQoNCiMjIDYuNiDSwL7dtuC49rHkwb+9+NDQt9bX6Q0KtLS9qNLAvt224Lj2seTBv7XEt9bX6brzo6zDv9K7tM4gYHN1bW1hcmlzZWC2vLvhsP7A69K7suO31tfpseTBvyAgDQoNCisg0sC+3WB5ZWFyYCwgYG1vbnRoYCwgYGRheWAgyP249rHkwb+31tfpDQpgYGB7cn0NCmRhaWx5IDwtIGdyb3VwX2J5KGZsaWdodHMsIHllYXIsIG1vbnRoLCBkYXkpDQoocGVyX2RheSAgIDwtIHN1bW1hcmlzZShkYWlseSwgZmxpZ2h0cyA9IG4oKSkpDQpgYGANCmBgYA0KIz4gU291cmNlOiBsb2NhbCBkYXRhIGZyYW1lIFszNjUgeCA0XQ0KIz4gR3JvdXBzOiB5ZWFyLCBtb250aCBbP10NCiM+IA0KIz4gICAgeWVhciBtb250aCAgIGRheSBmbGlnaHRzDQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+ICAgPGludD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICAgIDg0Mg0KIz4gMiAgMjAxMyAgICAgMSAgICAgMiAgICAgOTQzDQojPiAzICAyMDEzICAgICAxICAgICAzICAgICA5MTQNCiM+IDQgIDIwMTMgICAgIDEgICAgIDQgICAgIDkxNQ0KIz4gNSAgMjAxMyAgICAgMSAgICAgNSAgICAgNzIwDQojPiA2ICAyMDEzICAgICAxICAgICA2ICAgICA4MzINCiM+ICMgLi4uIHdpdGggMzU5IG1vcmUgcm93cw0KYGBgDQoNCisgYHN1bW1hcmlzZWAguvOjrLD+wOsgYGRheWAgseTBvw0KYGBge3J9DQoocGVyX21vbnRoIDwtIHN1bW1hcmlzZShwZXJfZGF5LCBmbGlnaHRzID0gc3VtKGZsaWdodHMpKSkNCmBgYA0KYGBgDQojPiBTb3VyY2U6IGxvY2FsIGRhdGEgZnJhbWUgWzEyIHggM10NCiM+IEdyb3VwczogeWVhciBbP10NCiM+IA0KIz4gICAgeWVhciBtb250aCBmbGlnaHRzDQojPiAgIDxpbnQ+IDxpbnQ+ICAgPGludD4NCiM+IDEgIDIwMTMgICAgIDEgICAyNzAwNA0KIz4gMiAgMjAxMyAgICAgMiAgIDI0OTUxDQojPiAzICAyMDEzICAgICAzICAgMjg4MzQNCiM+IDQgIDIwMTMgICAgIDQgICAyODMzMA0KIz4gNSAgMjAxMyAgICAgNSAgIDI4Nzk2DQojPiA2ICAyMDEzICAgICA2ICAgMjgyNDMNCiM+ICMgLi4uIHdpdGggNiBtb3JlIHJvd3MNCmBgYA0KDQorIGBzdW1tYXJpc2VgILrzo6yw/sDrIGBtb250aGAgseTBvw0KYGBge3J9DQoocGVyX3llYXIgIDwtIHN1bW1hcmlzZShwZXJfbW9udGgsIGZsaWdodHMgPSBzdW0oZmxpZ2h0cykpKQ0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDEgocEgMg0KIz4gICAgeWVhciBmbGlnaHRzDQojPiAgIDxpbnQ+ICAgPGludD4NCiM+IDEgIDIwMTMgIDMzNjc3Ng0KYGBgDQoNCiMjIDYuNyDIoc/7t9bX6Q0KYGBge3J9DQpkYWlseSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgICAgICAgICAgICAgIyBubyBsb25nZXIgZ3JvdXBlZCBieSBkYXRlDQogIHN1bW1hcmlzZShmbGlnaHRzID0gbigpKSAgIyBhbGwgZmxpZ2h0cw0KYGBgDQpgYGANCiM+ICMgQSB0aWJibGU6IDEgocEgMQ0KIz4gICBmbGlnaHRzDQojPiAgICAgPGludD4NCiM+IDEgIDMzNjc3Ng0KYGBgDQoNCiMgNyC31tfpseS7u6OoYG11dGF0ZSgpYCwgYGZpbHRlcigpYKOpDQorINXSs/bDv7j2t9bX6dbQx+m/9tfusu61xLPJ1LENCmBgYHtyfQ0KZmxpZ2h0c19zbWwgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBtb250aCwgZGF5KSAlPiUNCiAgZmlsdGVyKHJhbmsoZGVzYyhhcnJfZGVsYXkpKSA8IDEwKQ0KYGBgDQpgYGANCiM+IFNvdXJjZTogbG9jYWwgZGF0YSBmcmFtZSBbMywzMDYgeCA3XQ0KIz4gR3JvdXBzOiB5ZWFyLCBtb250aCwgZGF5IFszNjVdDQojPiANCiM+ICAgIHllYXIgbW9udGggICBkYXkgZGVwX2RlbGF5IGFycl9kZWxheSBkaXN0YW5jZSBhaXJfdGltZQ0KIz4gICA8aW50PiA8aW50PiA8aW50PiAgICAgPGRibD4gICAgIDxkYmw+ICAgIDxkYmw+ICAgIDxkYmw+DQojPiAxICAyMDEzICAgICAxICAgICAxICAgICAgIDg1MyAgICAgICA4NTEgICAgICAxODQgICAgICAgNDENCiM+IDIgIDIwMTMgICAgIDEgICAgIDEgICAgICAgMjkwICAgICAgIDMzOCAgICAgMTEzNCAgICAgIDIxMw0KIz4gMyAgMjAxMyAgICAgMSAgICAgMSAgICAgICAyNjAgICAgICAgMjYzICAgICAgMjY2ICAgICAgIDQ2DQojPiA0ICAyMDEzICAgICAxICAgICAxICAgICAgIDE1NyAgICAgICAxNzQgICAgICAyMTMgICAgICAgNjANCiM+IDUgIDIwMTMgICAgIDEgICAgIDEgICAgICAgMjE2ICAgICAgIDIyMiAgICAgIDcwOCAgICAgIDEyMQ0KIz4gNiAgMjAxMyAgICAgMSAgICAgMSAgICAgICAyNTUgICAgICAgMjUwICAgICAgNTg5ICAgICAgMTE1DQojPiAjIC4uLiB3aXRoIDMsMzAwIG1vcmUgcm93cw0KYGBgDQoNCisg1dKz9sL61+PSu7aozPW8/rXE1+mx8A0KYGBge3J9DQpwb3B1bGFyX2Rlc3RzIDwtIGZsaWdodHMgJT4lIA0KICBncm91cF9ieShkZXN0KSAlPiUgDQogIGZpbHRlcihuKCkgPiAzNjUpDQoNCnBvcHVsYXJfZGVzdHMNCmBgYA0KYGBgDQojPiBTb3VyY2U6IGxvY2FsIGRhdGEgZnJhbWUgWzMzMiw1NzcgeCAxOV0NCiM+IEdyb3VwczogZGVzdCBbNzddDQojPiANCiM+ICAgIHllYXIgbW9udGggICBkYXkgZGVwX3RpbWUgc2NoZWRfZGVwX3RpbWUgZGVwX2RlbGF5IGFycl90aW1lDQojPiAgIDxpbnQ+IDxpbnQ+IDxpbnQ+ICAgIDxpbnQ+ICAgICAgICAgIDxpbnQ+ICAgICA8ZGJsPiAgICA8aW50Pg0KIz4gMSAgMjAxMyAgICAgMSAgICAgMSAgICAgIDUxNyAgICAgICAgICAgIDUxNSAgICAgICAgIDIgICAgICA4MzANCiM+IDIgIDIwMTMgICAgIDEgICAgIDEgICAgICA1MzMgICAgICAgICAgICA1MjkgICAgICAgICA0ICAgICAgODUwDQojPiAzICAyMDEzICAgICAxICAgICAxICAgICAgNTQyICAgICAgICAgICAgNTQwICAgICAgICAgMiAgICAgIDkyMw0KIz4gNCAgMjAxMyAgICAgMSAgICAgMSAgICAgIDU0NCAgICAgICAgICAgIDU0NSAgICAgICAgLTEgICAgIDEwMDQNCiM+IDUgIDIwMTMgICAgIDEgICAgIDEgICAgICA1NTQgICAgICAgICAgICA2MDAgICAgICAgIC02ICAgICAgODEyDQojPiA2ICAyMDEzICAgICAxICAgICAxICAgICAgNTU0ICAgICAgICAgICAgNTU4ICAgICAgICAtNCAgICAgIDc0MA0KIz4gIyAuLi4gd2l0aCAzLjMyNmUrMDUgbW9yZSByb3dzLCBhbmQgMTIgbW9yZSB2YXJpYWJsZXM6DQojPiAjICAgc2NoZWRfYXJyX3RpbWUgPGludD4sIGFycl9kZWxheSA8ZGJsPiwgY2FycmllciA8Y2hyPiwgZmxpZ2h0IDxpbnQ+LA0KIz4gIyAgIHRhaWxudW0gPGNocj4sIG9yaWdpbiA8Y2hyPiwgZGVzdCA8Y2hyPiwgYWlyX3RpbWUgPGRibD4sDQojPiAjICAgZGlzdGFuY2UgPGRibD4sIGhvdXIgPGRibD4sIG1pbnV0ZSA8ZGJsPiwgdGltZV9ob3VyIDxkdHRtPg0KYGBgDQoNCisgt9bX6bzGy+PNs7zGwb8NCmBgYHtyfQ0KcG9wdWxhcl9kZXN0cyAlPiUgDQogIGZpbHRlcihhcnJfZGVsYXkgPiAwKSAlPiUgDQogIG11dGF0ZShwcm9wX2RlbGF5ID0gYXJyX2RlbGF5IC8gc3VtKGFycl9kZWxheSkpICU+JSANCiAgc2VsZWN0KHllYXI6ZGF5LCBkZXN0LCBhcnJfZGVsYXksIHByb3BfZGVsYXkpDQpgYGANCmBgYA0KIz4gU291cmNlOiBsb2NhbCBkYXRhIGZyYW1lIFsxMzEsMTA2IHggNl0NCiM+IEdyb3VwczogZGVzdCBbNzddDQojPiANCiM+ICAgIHllYXIgbW9udGggICBkYXkgIGRlc3QgYXJyX2RlbGF5IHByb3BfZGVsYXkNCiM+ICAgPGludD4gPGludD4gPGludD4gPGNocj4gICAgIDxkYmw+ICAgICAgPGRibD4NCiM+IDEgIDIwMTMgICAgIDEgICAgIDEgICBJQUggICAgICAgIDExICAgMS4xMWUtMDQNCiM+IDIgIDIwMTMgICAgIDEgICAgIDEgICBJQUggICAgICAgIDIwICAgMi4wMWUtMDQNCiM+IDMgIDIwMTMgICAgIDEgICAgIDEgICBNSUEgICAgICAgIDMzICAgMi4zNWUtMDQNCiM+IDQgIDIwMTMgICAgIDEgICAgIDEgICBPUkQgICAgICAgIDEyICAgNC4yNGUtMDUNCiM+IDUgIDIwMTMgICAgIDEgICAgIDEgICBGTEwgICAgICAgIDE5ICAgOS4zOGUtMDUNCiM+IDYgIDIwMTMgICAgIDEgICAgIDEgICBPUkQgICAgICAgICA4ICAgMi44M2UtMDUNCiM+ICMgLi4uIHdpdGggMS4zMTFlKzA1IG1vcmUgcm93cw0KYGBg